[BZOJ2791][Poi2012]Rendezvous

2791: [Poi2012]Rendezvous

Time Limit: 25 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

2 3
1 2
2 2
0 1
-1 -1

HINT

 

Source

[Submit][Status][Discuss]


n个点,n条边且每个点都有出边,显然是环套树森林。

先dfs把环套树拆成一堆树,倍增LCA。

先将x,y两个点倍增到环上,然后判断即可。

 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 }
View Code

 

posted @ 2016-02-15 19:19  xuruifan  阅读(673)  评论(1编辑  收藏  举报