1. 程式人生 > >BZOJ4998星球聯盟——LCT+並查集(LCT動態維護邊雙連通分量)

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 cut(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    f[x]=s[y][0]=0;
    pushup(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\n",sum[fx]);
        }
        else if(judge(fx)!=judge(fy))
        {
            link(fx,fy);
            printf("No\n");
        }
        else
        {
            reverse(fx);
            access(fy);
            splay(fy);
            size[fy]=sum[fy];
            dfs(fy,fy);
            s[fy][0]=0;
            printf("%d\n",sum[fy]);
        }
    }
}