[POI2012] 约会 Rendezvous

约会 Rendezvous

题目描述

给定一个有 $n $个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 $a_i​和 b_i$,求满足以下条件的 $x_i$​和$y_i$​:

  1. 从顶点$ a_i$​沿出边走 $x_i$​步与从顶点 $b_i$​沿出边走 $y_i$步到达的顶点相同。
  2. $max(x​_i​,y_i)$最小。
  3. 满足以上条件的情况下 $min(x_i,y_i​) $最小。
  4. 如果以上条件没有给出一个唯一的解,则还需要满足 $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;
}
View Code

 

posted @ 2019-07-15 08:53  Milk_Feng  阅读(125)  评论(0编辑  收藏  举报