[POI2012] 约会 Rendezvous
约会 Rendezvous
题目描述
给定一个有 $n $个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 $a_i和 b_i$,求满足以下条件的 $x_i$和$y_i$:
- 从顶点$ a_i$沿出边走 $x_i$步与从顶点 $b_i$沿出边走 $y_i$步到达的顶点相同。
- $max(x_i,y_i)$最小。
- 满足以上条件的情况下 $min(x_i,y_i) $最小。
- 如果以上条件没有给出一个唯一的解,则还需要满足 $x_i≥y_i$.
如果不存在这样的 $x_i$和 $y_i$,则 $x_i=y_i=−1$.
输入格式
第一行两个正整数 $n$ 和$ k(1≤n≤500 000,1≤k≤500)$,表示顶点数和询问个数。
接下来一行$ n $个正整数,第$ i $个数表示$ i$ 号顶点出边指向的顶点。
接下来 k 行表示询问,每行两个整数$ a_i$和$ b_i$.
输出格式
对每组询问输出两个整数 $x_i$和 $y_i$.
样例
样例输入
12 5
4 3 5 5 1 1 12 12 9 9 7 1
7 2
8 11
1 2
9 10
10 5
样例输出
2 3
1 2
2 2
0 1
-1 -1
数据范围与提示
对于$ 40\%$ 的数据,$n≤2000,k≤2000$
对于 $100\%$的数据,$1≤n≤500 000$,$1≤k≤500 000$.
题解
先用$tarjan$缩点,然后这个图就变成了一棵树。
1.如果两个点不在一棵树上,$x_i=y_i=-1$。
2.在一棵树上,对于这棵树求$lca$即可。因为每个节点只能连接其他的$1$个节点,所以对于每一棵树,有且仅有$1$个环。
最后如果他们的$lca$是个环的话,可以先预处理出每个节点在根的那个环中连接的位置的编号,最后减的话要分两种情况。
最后要卡一个常,来个$fread$和快读快输。
#include<iostream> #include<cstring> #include<cstdio> #define Reg register #define Maxn 500050 using namespace std; const int L = 1 << 20 | 1; char buffer[L], *S, *TT; #define getchar() ((S == TT && (TT = (S = buffer) + fread(buffer, 1, L, stdin), S == TT)) ? EOF : *S++) int n,st,k,tot,tpp,sum; int root[Maxn],vap[Maxn],rotsum[Maxn]; int fic[Maxn],fir[Maxn],vis[Maxn]; int stack[Maxn],dfn[Maxn],dep[Maxn],low[Maxn]; int pre[Maxn],gen[Maxn],tre[Maxn]; int pos[Maxn],poj[Maxn],tom[Maxn]; int fat[Maxn][25],len1[Maxn],len2[Maxn]; struct Tu {int st,ed,next;} lian[Maxn],liab[Maxn]; inline int max(Reg int x,Reg int y) {return x>y?x:y;} inline int min(Reg int x,Reg int y) {return x<y?x:y;} inline int read() { Reg int x=0; Reg char c=getchar(); Reg bool flag=0; while(c<'0'||c>'9') {if(c=='-') flag=1; c=getchar();} while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48); c=getchar();} if(flag) x=-x; return x; } inline void print(Reg int x) { if(x<0) {putchar('-'); x=-x;} if(x>9) print(x/10); putchar(x%10+48); return; } inline void add(Reg int x,Reg int y) { lian[++tot].st=x; lian[tot].ed=y; lian[tot].next=fir[x]; fir[x]=tot; return; } inline void app(Reg int x,Reg int y) { liab[++tpp].st=x; liab[tpp].ed=y; liab[tpp].next=fic[x]; fic[x]=tpp; return; } inline void tarjan(Reg int x) { dfn[x]=low[x]=++sum; stack[++stack[0]]=x; vis[x]=1; if(!dfn[pre[x]]) { tarjan(pre[x]); low[x]=min(low[x],low[pre[x]]); } else if(vis[pre[x]]) low[x]=min(low[x],dfn[pre[x]]); if(low[x]==dfn[x]) { tre[++tre[0]]=0; while(stack[stack[0]]!=x) { ++tre[tre[0]]; vis[stack[stack[0]]]=0; pos[stack[stack[0]]]=tre[0]; --stack[0]; } vis[stack[stack[0]]]=0; pos[stack[stack[0]]]=tre[0]; --stack[0]; } return; } inline void dfs(Reg int x,Reg int root) { gen[x]=root; vis[x]=1; for(Reg int i=fir[x];i;i=lian[i].next) { if(!vis[lian[i].ed]) { fat[lian[i].ed][0]=x; for(Reg int j=1;j<=18;++j) fat[lian[i].ed][j]=fat[fat[lian[i].ed][j-1]][j-1]; dep[lian[i].ed]=dep[x]+1; dfs(lian[i].ed,root); } } return; } inline int lca(Reg int x,Reg int y) { if(dep[x]<dep[y]) swap(x,y); if(x==y) return x; if(dep[x]!=dep[y]) { for(Reg int i=18;i>=0;--i) if(dep[fat[x][i]]>dep[y]) x=fat[x][i]; if(x==y) return x; x=fat[x][0]; } if(x==y) return x; for(Reg int i=18;i>=0;--i) { if(fat[x][i]!=fat[y][i]) { x=fat[x][i]; y=fat[y][i]; } } if(x==y) return x; return fat[x][0]; } inline void dfp(Reg int x,Reg int root) { vis[x]=1,poj[x]=root; for(Reg int i=fic[x];i;i=liab[i].next) if(!vis[liab[i].ed]) dfp(liab[i].ed,root); return; } int main() { n=read(); k=read(); for(Reg int i=1;i<=n;++i) {pre[i]=read(); app(pre[i],i);} for(Reg int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(Reg int i=1;i<=n;++i) { if(pos[i]!=pos[pre[i]]) add(pos[pre[i]],pos[i]); else if(!vap[pos[i]]) vap[pos[i]]=1,root[++root[0]]=pos[i]; } for(Reg int i=1;i<=n;++i) if(vap[pos[i]]) vis[i]=1,poj[i]=i,++rotsum[pos[i]],tom[++tom[0]]=i; for(Reg int i=1;i<=tom[0];++i) dfp(tom[i],tom[i]); for(Reg int i=1;i<=n;++i) { if(vap[pos[i]]) { st=i; vap[pos[i]]=0; for(Reg int j=1;j<=rotsum[pos[i]];++j) { if(!len1[st]) len1[st]=j; else len2[st]=j; st=pre[st]; } } } memset(vis,0,sizeof(vis)); if(!root[0]) root[++root[0]]=1; for(Reg int i=1;i<=root[0];++i) {dep[root[i]]=1; dfs(root[i],root[i]);} Reg int l1,l2,ans,lp1,lp2,lc1,lc2,p; for(Reg int i=1,x,y;i<=k;++i) { x=read(); y=read(); if(gen[pos[x]]!=gen[pos[y]]) {print(-1); putchar(' '); print(-1); putchar('\n');} else { p=lca(pos[x],pos[y]); if(p==gen[pos[x]]) { l1=poj[x],l2=poj[y]; if(l1==l2) {print(dep[pos[x]]-1); putchar(' '); print(dep[pos[y]]-1); putchar('\n');} else { if(len1[l1]<len1[l2]) ans=len1[l2]-len1[l1]; else ans=len1[l2]+rotsum[pos[l2]]-len1[l1]; lp1=dep[pos[x]]-1+ans,lp2=dep[pos[y]]-1; lc1=dep[pos[x]]-1,lc2=dep[pos[y]]-1+rotsum[gen[pos[x]]]-ans; if(max(lp1,lp2)!=max(lc1,lc2)) { if(max(lp1,lp2)<max(lc1,lc2)) {print(lp1); putchar(' '); print(lp2); putchar('\n');} else {print(lc1); putchar(' '); print(lc2); putchar('\n'); } } else if(min(lp1,lp2)!=min(lc1,lc2)) { if(min(lp1,lp2)<min(lc1,lc2)) {print(lp1); putchar(' '); print(lp2); putchar('\n');} else {print(lc1); putchar(' '); print(lc2); putchar('\n');} } else { if(lp1>=lp2) {print(lp1); putchar(' '); print(lp2); putchar('\n');} else {print(lc1); putchar(' '); print(lc2); putchar('\n');} } } } else {print(dep[pos[x]]-dep[p]); putchar(' '); print(dep[pos[y]]-dep[p]); putchar('\n');} } } return 0; }