2791: [Poi2012]Rendezvous
Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 95 Solved: 71
[Submit][Status][Discuss]
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行,每行两个整数。
Sample Input
12 5
4 3 5 5 1 1 12 12 9 9 7 1
7 2
8 11
1 2
9 10
10 5
4 3 5 5 1 1 12 12 9 9 7 1
7 2
8 11
1 2
9 10
10 5
Sample Output
2 3
1 2
2 2
0 1
-1 -1
1 2
2 2
0 1
-1 -1
HINT
Source
n个点,n条边且每个点都有出边,显然是环套树森林。
先dfs把环套树拆成一堆树,倍增LCA。
先将x,y两个点倍增到环上,然后判断即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #define N 500050 4 using namespace std; 5 inline int read() 6 { 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 10 return x*f; 11 } 12 int n,fa[N][20],root,q,circle[N],deep[N]; 13 int num[N],sum[N],tot,pos[N],vis[N]; 14 void findcircle(int x) 15 { 16 int now=x; 17 for(;;x=fa[x][0]) 18 { 19 if(vis[x]==now)break; 20 if(vis[x])return; 21 vis[x]=now; 22 } 23 tot++; 24 while(!circle[x]) 25 { 26 circle[x]=x; 27 deep[x]=1; 28 num[x]=++sum[tot]; 29 pos[x]=tot; 30 x=fa[x][0]; 31 } 32 } 33 void dfs(int x) 34 { 35 if(deep[x])return; 36 dfs(fa[x][0]); 37 circle[x]=circle[fa[x][0]]; 38 deep[x]=deep[fa[x][0]]+1; 39 for(int i=1;(1<<i)<deep[x];i++) 40 fa[x][i]=fa[fa[x][i-1]][i-1]; 41 } 42 inline int lca(int x,int y) 43 { 44 if(deep[x]<deep[y])swap(x,y); 45 int t=deep[x]-deep[y]; 46 for(int i=18;~i;i--) 47 if(t&(1<<i))x=fa[x][i]; 48 if(x==y)return x; 49 for(int i=18;~i;i--) 50 if(fa[x][i]!=fa[y][i]) 51 x=fa[x][i],y=fa[y][i]; 52 return fa[x][0]; 53 } 54 bool judge(int a,int b,int c,int d) 55 { 56 if(max(a,b)<max(c,d))return 1; 57 if(max(a,b)>max(c,d))return 0; 58 if(min(a,b)<min(c,d))return 1; 59 if(min(a,b)>min(c,d))return 0; 60 if(a>=b)return 1; 61 return 0; 62 } 63 int main() 64 { 65 n=read();q=read(); 66 for(int i=1;i<=n;i++) 67 fa[i][0]=read(); 68 for(int i=1;i<=n;i++) 69 findcircle(i); 70 for(int i=1;i<=n;i++) 71 if(!circle[i])dfs(i); 72 while(q--) 73 { 74 int x=read(),y=read(); 75 if(pos[circle[x]]!=pos[circle[y]]) 76 { 77 puts("-1 -1"); 78 continue; 79 } 80 if(circle[x]==circle[y]) 81 { 82 int t=lca(x,y); 83 printf("%d %d\n",deep[x]-deep[t],deep[y]-deep[t]); 84 continue; 85 } 86 int ans1=deep[x]-1,ans2=deep[y]-1,t=pos[circle[x]]; 87 x=num[circle[x]];y=num[circle[y]]; 88 int z1=(sum[t]+y-x)%sum[t],z2=sum[t]-z1; 89 if(judge(ans1+z1,ans2,ans1,ans2+z2)) 90 printf("%d %d\n",ans1+z1,ans2); 91 else printf("%d %d\n",ans1,ans2+z2); 92 } 93 }