1. 程式人生 > >[bzoj4998][LCT][並查集]星球聯盟

[bzoj4998][LCT][並查集]星球聯盟

Description

在遙遠的S星系中一共有N個星球,編號為1…N。其中的一些星球決定組成聯盟,以方便相互間的交流。但是,組成 聯盟的首要條件就是交通條件。初始時,在這N個星球間有M條太空隧道。每條太空隧道連線兩個星球,使得它們能 夠相互到達。若兩個星球屬於同一個聯盟,則必須存在一條環形線路經過這兩個星球,即兩個星球間存在兩條沒有 公共隧道的路徑。為了壯大聯盟的隊伍,這些星球將建設P條新的太空隧道。這P條新隧道將按順序依次建成。一條 新軌道建成後,可能會使一些星球屬於同一個聯盟。你的任務是計算出,在一條新隧道建設完畢後,判斷這條新軌 道連線的兩個星球是否屬於同一個聯盟,如果屬於同一個聯盟就計算出這個聯盟中有多少個星球。

Input

第1行三個整數N,M和P,分別表示總星球數,初始時太空隧道的數目和即將建設的軌道數目。 第2至第M+1行,每行兩個整數,表示初始時的每條太空隧道連線的兩個星球編號。 第M+2行至第M+P+1行,每行兩個整數,表示新建的太空隧道連線的兩個星球編號。 這些太空隧道按照輸入的順序依次建成。 1≤N,M,P≤200000

Output

輸出共P行。 如果這條新的太空隧道連線的兩個星球屬於同一個聯盟,就輸出一個整數,表示這兩個星球所在聯盟的星球數。 如果這條新的太空隧道連線的兩個星球不屬於同一個聯盟,就輸出”No”(不含引號)。

Sample Input

5 3 4

1 2

4 3

4 5

2 3

1 3

4 5

2 4

Sample Output

No

3

2

5

HINT

這裡寫圖片描述

題解

感覺還是很好想的啊.. LCT維護森林 每次加進來的邊要不就是樹邊要不就是非樹邊 樹邊直接加上,並查集維護連通性直接LCT太慢啦啦啦 非樹邊就會成環,設這條邊是(x,y) 把x~y的路徑提取出來,就是這個環 再用一個並查集維護點屬於的邊雙編號 暴力dfs維護並查集 別人的LCT模板怎麼這麼好看啊

不管了以後我的模板就是這個

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int fa1[210000],fa2[210000],siz[210000];
int findfa1(int x){return fa1[x]==x?fa1[x]:fa1[x]=findfa1(fa1[x]);}
int findfa2(int x){return fa2[x]==x?fa2[x]:fa2[x]=findfa2(fa2[x]);}
struct lct
{
    int son[2],f;
    int fz;
}tr[210000];
bool isroot(int x){return tr[findfa1(tr[x].f)].son[0]!=x&&tr[findfa1(tr[x].f)].son[1]!=x;}
void pushdown(int x)
{
    if(tr[x].fz)
    {
        swap(tr[x].son[0],tr[x].son[1]);
        if(tr[x].son[0])tr[tr[x].son[0]].fz^=1;
        if(tr[x].son[1])tr[tr[x].son[1]].fz^=1;
        tr[x].fz=0;
    }
}
void update(int x)
{
    if(!isroot(x))update(findfa1(tr[x].f));
    pushdown(x);
}
void rotate(int x)
{
    int y=findfa1(tr[x].f),z=findfa1(tr[y].f),d=(x==tr[y].son[1]);
    if(!isroot(y))tr[z].son[y==tr[z].son[1]]=x;
    tr[y].f=x;tr[x].f=z;tr[y].son[d]=tr[x].son[d^1];
    if(tr[x].son[d^1])tr[tr[x].son[d^1]].f=y;
    tr[x].son[d^1]=y;
}
void splay(int x)
{
    update(x);
    while(!isroot(x))
    {
        int y=findfa1(tr[x].f),z=findfa1(tr[y].f);
        if(!isroot(y))
        {
            if((x==tr[y].son[0])^(y==tr[z].son[0]))rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    int y=0;
    while(x!=0)
    {
        splay(x);
        tr[x].son[1]=y;
        if(y)tr[y].f=x;
        y=x;x=findfa1(tr[x].f);
    }
}
void markroot(int x){access(x);splay(x);tr[x].fz^=1;}
void link(int x,int y){markroot(x);tr[x].f=y;}
int sum;
void play(int x,int y)
{
    if(!x)return ;
    sum+=siz[x];
    if(x!=y)siz[y]+=siz[x],fa1[x]=y;
    play(tr[x].son[0],y);play(tr[x].son[1],y);
}
void lk(int x,int y)
{
    sum=0;
    if(findfa2(x)!=findfa2(y))
    {
        fa2[fa2[x]]=fa2[y];
        link(x,y);
    }
    else
    {
        markroot(x);access(y);splay(y);
        play(y,y);tr[y].son[0]=tr[y].son[1]=0;
    }
}
int n,m,P;
int main()
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    scanf("%d%d%d",&n,&m,&P);
    for(int i=1;i<=n;i++)fa1[i]=i,fa2[i]=i,siz[i]=1;
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        x=findfa1(x);y=findfa1(y);
        lk(x,y);
    }
    while(P--)
    {
        int x,y;scanf("%d%d",&x,&y);
        x=findfa1(x);y=findfa1(y);
    /*  int uu=findfa(x),vv=findfa(y);
        printf("%d     ",getroot(uu));
        printf("%d\n",getroot(vv));*/
        lk(x,y);
        if(sum==0)puts("No");
        else printf("%d\n",sum);
    }
    return 0;
}