zoukankan      html  css  js  c++  java
  • POI2012 约会 Rendezvous

    题目描述

    给定一个有 nnn 个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 aia_iai​​ 和 bib_ibi​​,求满足以下条件的 xix_ixi​​ 和 yiy_iyi​​:

    • 从顶点 aia_iai​​ 沿出边走 xix_ixi​​ 步与从顶点 bib_ibi​​ 沿出边走 yiy_iyi​​ 步到达的顶点相同。
    • max(xi,yi)i​​,yi​​) 最小。
    • 满足以上条件的情况下 min(xi,yi)i​​,yi​​) 最小。
    • 如果以上条件没有给出一个唯一的解,则还需要满足 xi≥yii​​yi​​.

    如果不存在这样的 xi,yi,输出 -1 -1i​​ 和 yiy_iyi​​,则 xi=yi=−1x_i = y_i = -1xi​​=yi​​=1.

    输入格式

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

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

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

    输出格式

    对每组询问输出两个整数 xi,yii​​ 和 yiy_iyi​​.

    样例

    样例输入

    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% 的数据,n2000,k2000.

    对于 100%100\%100% 的数据,1≤n≤500 000,1≤k≤500 000

       有向有环非联通图通常没什么素质。这题就是这样一个基环森林。。。。。首先要写一个对的LCA然后,可以用并查集来记录是否是一张图的,如果不是一张图上的直接-1 -1。在一张图上,用tarjan找到环(当然你有别的骚方法也没毛病),在环上的一圈点都有自己的子树,dfs的时候记录s[x]为x所在的子树,如果询问中两点在同一子树,直接LCA。如果不在,先找lca(x,s[x]),lca(y,s[y]);再找环上s[x]到s[y]的距离我是通过选定环上任意一点开始dfs,然后记录每一点dep值,dep值的差和环的size-差是两种路径,根据题意优先级判断。然后就结束了

      PS:(网站loj.ac上有这个题数据,不要问我怎么知道的)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N=500020;
    int fr[N],s[N],size[N],stack[N],q[N],c[N],b[N],d[N],low[N],du[N],a[N],dfn[N],tp[N],pt[N],fa[N][20],num,cnt,kt,top,n,k,tt;
    bool v[N],vs[N],ins[N];
    struct node{int fr,to,pr;}mo[N];
    struct qe{int a,b;};
    int rd()
    {
        char cc=getchar();
        int s=0,w=1;
        while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
        while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
        return s*w;
    }
    bool cmp(int x,int y)
    {
        return du[x]>du[y];
    }
    void add(int x,int y)
    {
        mo[++tt].fr=x;
        mo[tt].to=y;
        mo[tt].pr=fr[x];
        fr[x]=tt;du[x]++;
    }
    int find(int x)
    {
        if(x!=pt[x]) pt[x]=find(pt[x]);
        return pt[x];
    }
    void merge(int x,int y)
    {
        x=find(x);y=find(y);
        if(x!=y) pt[y]=x;
    }
    bool jud(int x,int y)
    {
        x=find(x);y=find(y);
        return x==y;
    }
    void tarjan(int x)
    {
        low[x]=dfn[x]=++num;
        stack[++top]=x;ins[x]=1;
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int y=mo[i].to;
            if(!dfn[y])
            {
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else if(ins[y]) low[x]=min(low[x],dfn[y]);
        }
        if(low[x]==dfn[x])
        {
            int y,s=0;++cnt;
            int tmp=find(stack[top]);
            do{
                y=stack[top--];
                
                size[cnt]++;
                c[y]=cnt;
                if(size[cnt]>1) b[tmp]=cnt,tp[tmp]=y;
                ins[y]=0;
            }while(x!=y);
        }
    }
    void dfs(int x,int str)
    {
        v[x]=1;s[x]=str;
        for(int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int to=mo[i].to;
            if(v[to])continue;
            fa[to][0]=x,d[to]=d[x]+1;
            //cout<<to<<" "<<d[to]<<endl;
            if(c[x]!=c[to])    dfs(to,str);
            else dfs(to,to);
        }
    }
    qe lca(int x,int y)
    {
        int ans1=0,ans2=0;
        qe ans;
        if(d[x]<d[y]) swap(x,y);
        for(int i=18;~i;i--)
            if(d[fa[x][i]]>=d[y]) x=fa[x][i],ans1+=(1<<i);
            ans.a=ans1,ans.b=0;
        if(x==y) return ans;
        for(int i=18;~i;i--)
            if(fa[x][i]!=fa[y][i])
            x=fa[x][i],ans1+=(1<<i),y=fa[y][i],ans2+=(1<<i);
            ans.a=ans1+1,ans.b=ans2+1;
        return ans;
    }
    int main()
    {
        //freopen("ran3c.in","r",stdin);
        //freopen("ran3c.ans","w",stdout);
        n=rd();k=rd();
        int x,y,tmp,rt;
        for(int i=1;i<=n;i++) pt[i]=i,a[i]=i;
        for(int i=1;i<=n;i++)
        {
            x=rd();
            merge(x,i);
            if(x==i) continue;
            add(x,i);
        }
        for(int i=1;i<=n;i++) if(!dfn[i]) d[i]=1,tarjan(i);
        for(int i=1;i<=n;i++) if(!vs[find(i)]) q[++kt]=find(i);
        for(int i=1;i<=kt;i++) if(!v[q[i]]) d[q[i]]=1,dfs(q[i],q[i]);
        //for(int i=1;i<=n;i++) printf("%d ",s[i]);
        for(int i=1;i<=k;i++)
        {
            x=rd();y=rd();
            if(!jud(x,y)) printf("-1 -1
    ");
            else
            {
                tmp=find(x);
                if(s[x]==s[y])
                {
                    qe te=lca(x,y);
                    if(d[x]>d[y])printf("%d %d
    ",te.a,te.b);
                    else printf("%d %d
    ",te.b,te.a);
                }
                else 
                {
                    int ans1=lca(x,s[x]).a,ans2=lca(y,s[y]).a,tmp1,tmp2;
                    x=s[x];y=s[y];
                    if(d[x]<d[y]) tmp2=d[y]-d[x],tmp1=size[b[tmp]]-tmp2;
                    else tmp1=d[x]-d[y],tmp2=size[b[tmp]]-tmp1;
                    //cout<<s[x]<<" "<<s[y]<<""<<" "<<ans1<<" "<<ans2<<" "<<tmp1<<" "<<tmp2<<endl;
                    //for(int i=fr[93];i;i=mo[i].pr) cout<<1<<" ";
                    if(max(ans1+tmp1,ans2)<max(ans1,ans2+tmp2))printf("%d %d
    ",ans1+tmp1,ans2);
                    else if(max(ans1+tmp1,ans2)>max(ans1,ans2+tmp2)) printf("%d %d
    ",ans1,ans2+tmp2);
                    else
                    {    
                        if(min(ans1+tmp1,ans2)<min(ans1,ans2+tmp2)) printf("%d %d
    ",ans1+tmp1,ans2);
                        else 
                        {
                            if(min(ans1+tmp1,ans2)>min(ans1,ans2+tmp2)) printf("%d %d
    ",ans1,ans2+tmp2);
                            else
                            {
                                if(ans1+tmp1>=ans2) printf("%d %d
    ",ans1+tmp1,ans2);
                                else printf("%d %d
    ",ans1,ans2+tmp2);
                            }
                        }
                    }
                }
            }
        }
    }
    /*
    g++ 1.cpp -o 1
    ./1
    12 5
    4 3 5 5 1 1 12 12 9 9 7 1
    7 2
    8 11
    1 2
    9 10
    10 5
    */
    View Code
    Zeit und Raum trennen dich und mich.时空将你我分开。
  • 相关阅读:
    实验四 决策树算法及应用
    实验三 朴素贝叶斯算法及应用
    实验二 K-近邻算法及应用
    实验一 感知器及其应用
    实验三 面向对象分析与设计
    实验二 结构化分析与设计
    实验一 软件开发文档与工具的安装与使用
    个人作业三-ATM管理系统
    个人作业二-举例分析流程图与活动图的区别与联系
    第一次个人作业-四则运算题目生成程序(计算机181 张博闻)
  • 原文地址:https://www.cnblogs.com/starsing/p/11178583.html
Copyright © 2011-2022 走看看