BZOJ2791: [Poi2012]Rendezvous

来源:互联网 发布:linux oracle服务很卡 编辑:程序博客网 时间:2024/06/05 23:56

题目大意:有n个点,每个点有一条出边,再给出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。

2,3,4条件是搞笑的,没有spj,然后就得手动弄出一组定义的解

首先这个图可以看成一堆环,环上每个节点有一个有向的树指向它(大小可能为0)

然后求x,y的话可以分三种情况讨论

1.a,b不在一个联通块上, 则无解

2.a,b在同一个环的同一个节点的子树下,那就是都走到LCA

3.那肯定是两个点都走到环上,然后其中一个向另一个移动,这种情况只需要算出两个解然后根据他给的比较规则来选一个更优的

 

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 500010using namespace std;int a[N];bool vis[N],zai[N],inc[N];int s[N],t;int fa[N][21],bel[N],num[N],tree[N],d[N];int tot[N],cnt;void dfs(int x){vis[x]=true;t++;s[t]=x;zai[x]=true;if(vis[a[x]]){if(!zai[a[x]]) bel[x]=bel[a[x]],fa[x][0]=a[x],d[x]=d[a[x]]+1,tree[x]=tree[a[x]];else{cnt++;while(s[t]!=a[x]){inc[s[t]]=true;t--;}inc[s[t]]=true;tree[x]=x;bel[x]=cnt;tot[cnt]=1;num[x]=1;}zai[x]=false;return;}dfs(a[x]);if(inc[x]){tree[x]=x;bel[x]=cnt;tot[cnt]++;num[x]=tot[cnt];}else{d[x]=d[a[x]]+1;tree[x]=tree[a[x]];bel[x]=bel[a[x]];fa[x][0]=a[x];}zai[x]=false;}int LCA(int x,int y){int i=20;if(d[x]<d[y]) swap(x,y);while(d[x]>d[y]){if(d[x]-d[y]>=(1<<i)) x=fa[x][i];i--;}if(x==y) return x;i=20;while(fa[x][0]!=fa[y][0]){if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];i--;}return fa[x][0];}int main(){int n,q;scanf("%d%d",&n,&q);int i,j,x,y,z,ans1,ans2,cur1,cur2;for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=1;i<=n;i++)if(!vis[i]) dfs(i);for(j=1;j<=20;j++)for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];while(q--){scanf("%d%d",&x,&y);if(bel[x]!=bel[y]) printf("-1 -1\n");else if(tree[x]==tree[y]){z=LCA(x,y);printf("%d %d\n",d[x]-d[z],d[y]-d[z]);}else{int tmp1=tree[x],tmp2=tree[y];ans1=d[x]+num[tmp1]-num[tmp2]+(num[tmp1]>=num[tmp2]?0:tot[bel[x]]);ans2=d[y];cur1=d[x];cur2=d[y]+num[tmp2]-num[tmp1]+(num[tmp2]>=num[tmp1]?0:tot[bel[x]]);if(max(ans1,ans2)!=max(cur1,cur2)){if(max(ans1,ans2)>max(cur1,cur2))ans1=cur1,ans2=cur2;}else if(min(ans1,ans2)!=min(cur1,cur2)){if(min(ans1,ans2)>min(cur1,cur2))ans1=cur1,ans2=cur2;}else if(ans1<ans2)swap(ans1,ans2);printf("%d %d\n",ans1,ans2);}}}


 

0 0