Description
给定一个n个顶点的有向图,每个顶点有且仅有一条出边。
对于顶点i,记它的出边为(i, a[i])。
再给出q组询问,每组询问由两个顶点a、b组成,要求输出满足下面条件的x、y:
1. 从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。
2. 在满足条件1的情况下max(x,y)最小。
3. 在满足条件1和2的情况下min(x,y)最小。
4. 在满足条件1、2和3的情况下x>=y。
如果不存在满足条件1的x、y,输出-1 -1。
Input
第一行两个正整数n和q (n,q<=500,000)。
第二行n个正整数a[1],a[2],...,a[n] (a[i]<=n)。
下面q行,每行两个正整数a,b (a,b<=n),表示一组询问。
Output
输出q行,每行两个整数。
思路:其实我觉得基环树题就是暴力模拟题……先找环,然后有多种情况,在环上某点的同一子树下,在环上不同子树下,不在同一联通块内,一一处理即可
#include<bits/stdc++.h> using namespace std; const int N = 5e5 + 10; int head[N], now; struct edges{ int to, next, w; }edge[N<<1]; void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;} void read(int &x){ int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } int n, q, dfn[N], sz, pre[N], tot, c[N], dict[N], bel[N], fa[N][22], dep[N], pos[N]; vector<int> cir[N]; void fcur(int x){ dfn[x] = ++sz; bel[x] = tot; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == pre[x]) continue; if(dfn[v]){ if(dfn[v] < dfn[x]) continue; cir[tot].push_back(x); c[x] = tot; for(; x != v; v = pre[v]){ cir[tot].push_back(v), c[v] = tot; } }else pre[v] = x, fcur(v); } return ; } void dfs(int x, int father, int root){ dict[x] = root; fa[x][0] = father; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == father || c[v]) continue; dep[v] = dep[x] + 1; dfs(v, x, root); } } int LCA(int u,int v){ if(dep[u]<dep[v]) swap(u,v); int k=dep[u]-dep[v]; for(int i=0;i<=20;i++) if((1<<i)&k) u=fa[u][i]; if(u==v) return u; for(int i=20;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } void dfs2(int x, int step){ pos[x] = step; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(edge[i].w && !pos[v]) dfs2(v, step + 1); } } int main(){ read(n), read(q); int x, y; for(int i = 1; i <= n; i++){ read(x); add(i, x, 1), add(x, i, 0); } for(int i = 1; i <= n; i++){ if(!dfn[i]){ sz = 0; tot++; fcur(i); } } for(int i = 1; i <= tot; i++){ dfs2(cir[i][0], 1); for(int j = 0; j < cir[i].size(); j++){ x = cir[i][j]; dict[x] = x; dfs(x, x, x); } } for(int j = 0; j <= 20; j++) for(int i = 1; i <= n; i++) fa[i][j + 1] = fa[fa[i][j]][j]; while(q--){ scanf("%d%d", &x, &y); if(bel[x] != bel[y]){ puts("-1 -1"); continue; }else if(dict[x] == dict[y]){ int lca = LCA(x, y); printf("%d %d ", dep[x] - dep[lca], dep[y] - dep[lca]); }else{ int rt1 = dict[x], rt2 = dict[y], siz = cir[bel[x]].size(); int s1 = dep[x] - dep[rt1], s2 = dep[y] - dep[rt2]; int k1, k2; if(pos[rt1] < pos[rt2]) k1 = pos[rt2] - pos[rt1], k2 = siz - k1; else k2 = pos[rt1] - pos[rt2], k1 = siz - k2; int tmp1 = s1 + k1, tmp2 = s2 + k2; if(max(tmp1, s2) != max(s1, tmp2)){ if(max(tmp1, s2) > max(s1, tmp2)) printf("%d %d ", s1, tmp2); else printf("%d %d ", tmp1, s2); continue; } else if(min(tmp1, s2) != min(s1, tmp2)){ if(min(tmp1, s2) > min(s1, tmp2)) printf("%d %d ", s1, tmp2); else printf("%d %d ", tmp1, s2); continue; } else{ if(tmp1 >= s2) printf("%d %d ", tmp1, s2); else printf("%d %d ", s1, tmp2); } } } return 0; }