zoukankan      html  css  js  c++  java
  • [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
    ",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
    ",ans1+z1,ans2);
    91         else printf("%d %d
    ",ans1,ans2+z2);
    92     }
    93 }
    View Code
  • 相关阅读:
    hisi3516/3519开发(二)—xshell连接串口
    linux svn使用
    IdentityServer4 源码介绍
    想写博客
    # VS2019 快捷键插入当前时间
    # 使用 vscode markdown 遇到的问题
    # 学Vue
    teXt使用
    Linux基础
    NopCommerce(Core)学习目录
  • 原文地址:https://www.cnblogs.com/xuruifan/p/5191201.html
Copyright © 2011-2022 走看看