其他分享
首页 > 其他分享> > [POI2012] 约会 Rendezvous

[POI2012] 约会 Rendezvous

作者:互联网

约会 Rendezvous

题目描述

给定一个有 n 个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 ai​和 bi,求满足以下条件的 x​i​和y​i​:

  1. 从顶点 ai​沿出边走 xi​步与从顶点 bi​沿出边走 yi步到达的顶点相同。
  2. max(x​i​,y​i​)最小。
  3. 满足以上条件的情况下 min(x​i​,y​i​) 最小。
  4. 如果以上条件没有给出一个唯一的解,则还需要满足 xi≥yi.

如果不存在这样的 xi​和 yi,则 xi=yi=−1.

输入格式

第一行两个正整数 n 和 k(1≤n≤500 000,1≤k≤500),表示顶点数和询问个数。

接下来一行 n 个正整数,第 i 个数表示 i 号顶点出边指向的顶点。

接下来 k 行表示询问,每行两个整数 a​i​和 b​i​.

输出格式

对每组询问输出两个整数 x​i​和 yi​.

样例

样例输入

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.如果两个点不在一棵树上,xi=yi=-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

 

标签:return,vis,POI2012,约会,fat,Reg,int,Rendezvous,stack
来源: https://www.cnblogs.com/Milk-Feng/p/11186922.html