这题就是一道需要分类讨论的图论。。
注意到题目中每个点只有一条出边,也就是说给出的图是一个内向的基环树森林。
首先进行预处理:
p[][]
。cycdis
。下面开始处理查询:
事实上,这题的难点在于如何处理需要的信息,主体的查询并不复杂。
更多细节见代码。
《8000ms 与 TLE》
// Problem: 会合 // Contest: AcWing // URL: https://www.acwing.com/problem/content/394/ // Memory Limit: 128 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #pragma GCC optimize("O3") #include<bits/stdc++.h> using namespace std; #define debug(x) cerr << #x << ": " << (x) << endl #define endl '\n' #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define dwn(i,a,b) for(int i=(a);i>=(b);i--) #define pb push_back #define all(x) (x).begin(), (x).end() #define x first #define y second using pii = pair<int, int>; using ll = long long; inline void read(int &x){ int s=0; x=1; char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();} while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar(); x*=s; } const int N=5e5+50; int n, Q; int w[N]; vector<int> g[N]; int f[N]; int find(int x){ return x==f[x]? x: f[x]=find(f[x]); } bool vis[N], isrt[N]; int p[N][20], dep[N]; void dfs(int u, int fa, int d, int fir, int sec){ vis[u]=true; dep[u]=d; if(!isrt[u]){ p[u][0]=fa; rep(i,1,19) p[u][i]=p[p[u][i-1]][i-1]; } else p[u][0]=u; for(auto go: g[u]){ if(u==sec && go==fir) continue; dfs(go, u, (isrt[go]? 0: d+1), fir, sec); } } pii lca(int u, int v){ bool swp=false; if(dep[u]<dep[v]) swap(u, v), swp=true; dwn(i,19,0) if(dep[u]-(1<<i)>=dep[v]) u=p[u][i]; if(u==v) return {u, v}; dwn(i,19,0){ int pu=p[u][i], pv=p[v][i]; if(pu!=pv && !isrt[pu]){ u=pu, v=pv; } } return swp==false? (pii){p[u][0], p[v][0]}: (pii){p[v][0], p[u][0]}; } int cycn[N]; int cid[N], ctot, sz[N]; int cycdis(int sz, int u, int v){ int x=cycn[u], y=cycn[v]; if(y>x) return y-x; return sz-(x-y); } int main(){ cin>>n>>Q; rep(i,1,n) f[i]=i; rep(i,1,n){ read(w[i]); g[w[i]].pb(i); f[find(i)]=find(w[i]); } rep(i,1,n) if(!vis[i]){ int u=i; while(!vis[u]) vis[u]=true, u=w[u]; int rt=u; int ts=0; ++ctot; do{ isrt[rt]=true; cycn[rt]=++ts; cid[rt]=ctot; sz[ctot]++; rt=w[rt]; }while(rt!=u); dfs(u, 0, 0, u, w[u]); } while(Q--){ int u, v; read(u), read(v); if(find(u)!=find(v)){ puts("-1 -1"); continue; } auto [x, y]=lca(u, v); if(x==y){ cout<<dep[u]-dep[x]<<' '<<dep[v]-dep[x]<<endl; continue; } int dx=dep[u]-dep[x], dy=dep[v]-dep[y]; int fir=cycdis(sz[cid[x]], x, y); int sec=cycdis(sz[cid[x]], y, x); if(max(dx+fir, dy)!=max(dx, dy+sec)){ if(max(dx+fir, dy)<max(dx, dy+sec)) cout<<dx+fir<<' '<<dy<<endl; else cout<<dx<<' '<<dy+sec<<endl; } else if(min(dx+fir, dy)!=min(dx, dy+sec)){ if(min(dx+fir, dy)<min(dx, dy+sec)) cout<<dx+fir<<' '<<dy<<endl; else cout<<dx<<' '<<dy+sec<<endl; } else cout<<dx+fir<<' '<<dy<<endl; } return 0; }