zoukankan      html  css  js  c++  java
  • BZOJ4998星球联盟——LCT+并查集(LCT动态维护边双连通分量)

    题目描述

    在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成
    联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能
    够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有
    公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条
    新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨
    道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

    输入

    第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
    第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
    第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。
    这些太空隧道按照输入的顺序依次建成。
    1≤N,M,P≤200000

    输出

    输出共P行。
    如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。
    如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出"No"(不含引号)。

    样例输入

    5 3 4
    1 2
    4 3
    4 5
    2 3
    1 3
    4 5
    2 4

    样例输出

    No
    3
    2
    5

    提示

    BZOJ2959弱化版

    如果两个星球属于同一个联盟,那么他们就属于一个点双,用LCT维护点双缩点后的树,用两个并查集分别维护每个点属于哪个点双及点之间连通性,加边时分两种情况讨论即可。具体操作参见BZOJ2959。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<bitset>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define pr pair<int,int>
    #define ll long long
    using namespace std;
    int g[200010];
    int fa[200010];
    int f[200010];
    int s[200010][2];
    int sum[200010];
    int st[200010];
    int r[200010];
    int size[200010];
    int n,m,p;
    int opt;
    int x,y;
    int find(int x)
    {
        if(fa[x]==x)
        {
            return x;
        }
        return fa[x]=find(fa[x]);
    }
    int judge(int x)
    {
        if(g[x]==x)
        {
            return x;
        }
        return g[x]=judge(g[x]);
    }
    int is_root(int rt)
    {
        return rt!=s[find(f[rt])][0]&&rt!=s[find(f[rt])][1];
    }
    int get(int rt)
    {
        return rt==s[find(f[rt])][1];
    }
    void pushup(int rt)
    {
        sum[rt]=sum[s[rt][0]]+sum[s[rt][1]]+size[rt];
    }
    void pushdown(int rt)
    {
        if(r[rt])
        {
            swap(s[rt][0],s[rt][1]);
            r[s[rt][0]]^=1;
            r[s[rt][1]]^=1;
            r[rt]^=1;
        }
    }
    void rotate(int rt)
    {
        int fa=find(f[rt]);
        int anc=find(f[fa]);
        int k=get(rt);
        if(!is_root(fa))
        {
            s[anc][get(fa)]=rt;
        }
        s[fa][k]=s[rt][k^1];
        f[s[fa][k]]=fa;
        s[rt][k^1]=fa;
        f[fa]=rt;
        f[rt]=anc;
        pushup(fa);
        pushup(rt);
    }
    void splay(int rt)
    {
        int top=0;
        st[++top]=rt;
        for(int i=rt;!is_root(i);i=find(f[i]))
        {
            st[++top]=find(f[i]);
        }
        for(int i=top;i>=1;i--)
        {
            pushdown(st[i]);
        }
        for(int fa;!is_root(rt);rotate(rt))
        {
            if(!is_root(fa=find(f[rt])))
            {
                rotate(get(fa)==get(rt)?fa:rt);
            }
        }
    }
    void access(int rt)
    {
        for(int x=0;rt;x=rt,rt=find(f[rt]))
        {
            splay(rt);
            s[rt][1]=x;
            pushup(rt);
        }
    }
    void reverse(int rt)
    {
        access(rt);
        splay(rt);
        r[rt]^=1;
    }
    void link(int x,int y)
    {
        reverse(x);
        f[x]=y;
        g[g[x]]=g[y];
    }
    void dfs(int x,int rt)
    {
        fa[x]=rt;
        if(s[x][0])
        {
            dfs(s[x][0],rt);
        }
        if(s[x][1])
        {
            dfs(s[x][1],rt);
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1;i<=n;i++)
        {
            fa[i]=g[i]=i;
            size[i]=sum[i]=1;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            int fx=find(x);
            int fy=find(y);
            if(fx!=fy)
            {
                if(judge(fx)!=judge(fy))
                {
                    link(fx,fy);
                }
                else
                {
                    reverse(fx);
                    access(fy);
                    splay(fy);
                    size[fy]=sum[fy];
                    dfs(fy,fy);
                    s[fy][0]=0;
                }
            }
        }
        for(int i=1;i<=p;i++)
        {
            scanf("%d%d",&x,&y);
            int fx=find(x);
            int fy=find(y);
            if(fx==fy)
            {
                reverse(fx);
                access(fy);
                splay(fy);
                printf("%d
    ",sum[fx]);
            }
            else if(judge(fx)!=judge(fy))
            {
                link(fx,fy);
                printf("No
    ");
            }
            else
            {
                reverse(fx);
                access(fy);
                splay(fy);
                size[fy]=sum[fy];
                dfs(fy,fy);
                s[fy][0]=0;
                printf("%d
    ",sum[fy]);
            }
        }
    }
  • 相关阅读:
    Raid5 Raid10性能测试
    MetaData_model_package
    UBoot命令说明
    ubuntu 12.10 配置一个Apache+MySQL+phpMyAdmin环境
    SSH服务器
    VC2008使用boost库方式
    嵌入式Web服务器BOA移植
    利用matlab将数据写入指定列的方法
    error LNK2019: 无法解析的外部符号,解决办法
    在CYGWIN下编译和运行软件Bundler ,以及PMVS,CMVS的编译与使用
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9959422.html
Copyright © 2011-2022 走看看