bzoj 2791 [Poi2012]Rendezvous 倍增lca 基环树

来源:互联网 发布:知乎恐怖提问 编辑:程序博客网 时间:2024/06/08 04:52

这是一个基环内向树森林。两个点如果在一个子树中,直接倍增lca。
否则两个点先走到环上,然后一个点不动,另一个点走到这个点。

#include <bits/stdc++.h>using namespace std;#define N 510000int n,q,top,cnt;int fa[N][21];int vis[N],st[N],inc[N],root[N],deep[N];int bel[N],ins[N],num[N],sum[N];void dfs(int x){    st[++top]=x;vis[x]=ins[x]=1;    int y=fa[x][0];    if(ins[y])    {        int t=0;        bel[y]=++cnt;inc[y]=1;num[y]=t;        fa[y][0]=0;root[y]=y;        for(int i=top;st[i]!=y;i--)        {               inc[st[i]]=1,bel[st[i]]=cnt;            root[st[i]]=st[i];num[st[i]]=++t;            fa[st[i]][0]=0;        }        sum[cnt]=t+1;ins[x]=0;        return;    }    if(!vis[y])dfs(y);    ins[x]=0;    if(inc[x])return;    bel[x]=bel[y];deep[x]=deep[y]+1;    root[x]=root[y];    for(int i=1;i<=20;i++)        fa[x][i]=fa[fa[x][i-1]][i-1];}int lca(int x,int y){    if(deep[x]<deep[y])swap(x,y);    for(int i=20;i>=0;i--)        if(deep[fa[x][i]]>=deep[y])            x=fa[x][i];    if(x==y)return x;    for(int i=20;i>=0;i--)        if(fa[x][i]!=fa[y][i])            x=fa[x][i],y=fa[y][i];    return fa[x][0];}int main(){    scanf("%d%d",&n,&q);    for(int i=1;i<=n;i++)        scanf("%d",&fa[i][0]);    for(int i=1;i<=n;i++)        if(!vis[i]){top=0;dfs(i);}    for(int a,b,x,y;q--;)    {        scanf("%d%d",&a,&b);        if(bel[a]!=bel[b])            {puts("-1 -1");continue;}        if(root[a]==root[b])        {            int t=lca(a,b);            x=deep[a]-deep[t],y=deep[b]-deep[t];            printf("%d %d\n",x,y);        }        else        {            x=deep[a];y=deep[b];            a=root[a];b=root[b];            int m=sum[bel[a]];            int x1=x+(num[a]-num[b]+m)%m,y1=y;            int x2=x,y2=y+(num[b]-num[a]+m)%m;            int mx1=max(x1,y1),mx2=max(x2,y2),mn1=min(x1,y1),mn2=min(x2,y2);            if(mx1<mx2||(mx1==mx2&&mn1<mn2)||(mx1==mx2&&mn1==mn2&&x1>=y1))                printf("%d %d\n",x1,y1);            else printf("%d %d\n",x2,y2);        }    }    return 0;}
0 0
原创粉丝点击