思路
首先,你管一道洛谷紫题叫做简单我还是很不能理解的
说回正题,a,b的位置一共三种情况。
1. 不在一个连通块上,直接输出-1。需要先预处理dfs出每一个连通块
2. 在同一棵子树上,退化为lca模板,预处理一下每一棵子树的祖先数组即可
3. 不在同一棵子树上,但在同一个连通块上,处理a、b到根节点的距离,特判一下a的根节点到b的根节点还是b的根节点到a的根节点更优
具体细节看代码
温馨提示:使用endl会tle,cin不优化要tle
C++ 代码
#pragma GCC optimize(3)//O3优化
#include<bits/stdc++.h>
using namespace std;
int n,q;
vector<int>gra[500010];
//vector建无向图
int fa[500010][21],rt[500010],cc[500010],isrt[500010],depth[500010],num[500010],cntt[500010];
//fa为倍增lca的祖先数组,rt为点在基环树上的根节点,isrt表示是否为根节点,depth表示深度(lca里用),num是根节点的编号,cntt表示一棵基环树上根节点的数量
bool vis[500010];
//vis在找环时用到
void dfs(int v,int x){//标记联通块上所有的点
if(cc[v]==x)return;
cc[v]=x;
for(auto&u:gra[v])dfs(u,x);
}
void dfss(int v,int x){//处理深度,和根节点
if(rt[v]==x)return;
rt[v]=x;
for(auto&u:gra[v])if(!isrt[u]&&!depth[u])depth[u]=depth[v]+1,dfss(u,x);
}
int lca(int a,int b){//lca模板
if(depth[a]<depth[b])swap(a,b);
for(int k=20;k>=0;k--)if(depth[fa[a][k]]>=depth[b])a=fa[a][k];
if(a==b)return a;
for(int k=20;k>=0;k--)if(fa[a][k]!=fa[b][k]){
a=fa[a][k];
b=fa[b][k];
}
return fa[a][0];
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);//读入优化
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>fa[i][0],gra[fa[i][0]].push_back(i),gra[i].push_back(fa[i][0]);
for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];//处理倍增祖先数组
int cnt=0;
for(int i=1;i<=n;i++)if(!cc[i]){//判断该连通块是否访问过
dfs(i,++cnt);//标记访问
int v=i;
for(;!vis[v];v=fa[v][0])vis[v]=1;//经典基环树上找环
for(;vis[v];v=fa[v][0])vis[v]=0,isrt[v]=cnt,depth[v]=0;//处理根节点信息
for(;!vis[v];v=fa[v][0])vis[v]=1,dfss(v,v);//处理深度以及当前点的根节点
int j=0;
for(;vis[v];v=fa[v][0])num[v]=j,vis[v]=0,j++;//标记根节点编号
for(;!vis[v];v=fa[v][0])vis[v]=1,cntt[v]=j;//根节点数量
}
for(int i=0;i<q;i++){
int a,b;
cin>>a>>b;
if(cc[a]!=cc[b])cout<<"-1 -1\n";//不在同一个连通块上
else if(rt[a]==rt[b]){//在同一棵树上
int c=lca(a,b);
cout<<depth[a]-depth[c]<<' '<<depth[b]-depth[c]<<'\n';
}
else{
int x=depth[a]-depth[rt[a]],y=depth[b]-depth[rt[b]];//到根节点的距离
int x1=x+(cntt[rt[a]]+num[rt[b]]-num[rt[a]])%cntt[rt[a]],y1=y+(cntt[rt[b]]+num[rt[a]]-num[rt[b]])%cntt[rt[b]];//a->b和b->a的距离
if(max(x,y1)<max(x1,y)||max(x,y1)==max(x1,y)&&min(x,y1)<min(x1,y)||max(x,y1)==max(x1,y)&&min(x,y1)==min(x1,y)&&x>=y1)cout<<x<<' '<<y1<<'\n';
else cout<<x1<<' '<<y<<'\n';
}
}
}