1. 程式人生 > >【刷題】BZOJ 4998 星球聯盟

【刷題】BZOJ 4998 星球聯盟

又是 sam 表示 但是 新建 spl include AD getc

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

技術分享圖片

Solution

又是一個LCT的特殊操作——維護邊雙
其實就是縮點
LCT裏真正維護的是那些縮了點之後的聯通塊的信息,稱之為天人交戰,與原圖中的單個節點毫無關系(除了本身是一個聯通塊的),它的層次高那麽一層
所以每次調用LCT的函數之前,都要先找到它所屬的聯通塊的編號,再用這個編號在LCT裏進行操作。那麽每次跳節點的時候,要保證操作的節點是在天人層次,每次就跳到那個節點指向的聯通塊上去
如何記錄每個點所屬的聯通塊?用一個類似並查集的東西,記錄它指向的聯通塊
然後在LCT外用一個真正的並查集記錄兩點的連通性

對於維護聯通塊,如果 \(u\)\(v\) 已經聯通,再要連上一條邊,那肯定就有環了,也就有邊雙了,那這一個環裏的聯通塊全都要縮起來,那就一個dfs,遍歷環裏的所有聯通塊,把他們都指向一個聯通塊就行了,同時維護題目要求的size

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXN=200000+10;
int n,m,p,fa[MAXN];
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LCT{
    int ch[MAXN][2],fa[MAXN],rev[MAXN],size[MAXN],stack[MAXN],cnt,bel[MAXN];
    inline void init()
    {
        for(register int i=1;i<=n;++i)bel[i]=i,size[i]=1;
    }
    inline int find(int x)
    {
        return bel[x]==x?x:bel[x]=find(bel[x]);
    }
    inline bool nroot(int x)
    {
        return lc(find(fa[x]))==x||rc(find(fa[x]))==x;
    }
    inline void reverse(int x)
    {
        std::swap(lc(x),rc(x));
        rev[x]^=1;
    }
    inline void dfs(int x,int rt)
    {
        if(lc(x))dfs(lc(x),rt);
        if(rc(x))dfs(rc(x),rt);
        if(x!=rt)bel[x]=rt,size[rt]+=size[x];
    }
    inline void pushdown(int x)
    {
        if(rev[x])
        {
            if(lc(x))reverse(lc(x));
            if(rc(x))reverse(rc(x));
            rev[x]=0;
        }
    }
    inline void rotate(int x)
    {
        int f=find(fa[x]),p=find(fa[f]),c=(rc(f)==x);
        if(nroot(f))ch[p][rc(p)==f]=x;
        fa[ch[f][c]=ch[x][c^1]]=f;
        fa[ch[x][c^1]=f]=x;
        fa[x]=p;
    }
    inline void splay(int x)
    {
        cnt=0;
        stack[++cnt]=x;
        for(register int i=x;nroot(i);i=find(fa[i]))stack[++cnt]=find(fa[i]);
        while(cnt)pushdown(stack[cnt--]);
        for(register int y=find(fa[x]);nroot(x);rotate(x),y=find(fa[x]))
            if(nroot(y))rotate((lc(y)==x)==(lc(find(fa[y]))==y)?y:x);
    }
    inline void access(int x)
    {
        for(register int y=0;x;x=find(fa[y=x]))splay(x),rc(x)=y;
    }
    inline void makeroot(int x)
    {
        access(x);splay(x);reverse(x);
    }
    inline void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    inline void link(int x,int y)
    {
        makeroot(x);fa[x]=y;
    }
};
LCT T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline int found(int x)
{
    if(fa[x]!=x)fa[x]=found(fa[x]);
    return fa[x];
}
inline int add(int u,int v)
{
    u=T.find(u),v=T.find(v);
    int x=found(u),y=found(v);
    if(u==v)return T.size[v];
    if(x!=y)
    {
        fa[x]=y,T.link(u,v);
        return -1;
    }
    T.split(u,v);T.dfs(T.ch[v][0],v);
    return T.size[v];
}
int main()
{
    read(n);read(m);read(p);
    T.init();
    for(register int i=1;i<=n;++i)fa[i]=i;
    for(register int i=1;i<=m;++i)
    {
        int u,v;
        read(u);read(v);
        add(u,v);
    }
    while(p--)
    {
        int u,v,res;
        read(u);read(v);
        if(~(res=add(u,v)))write(res,'\n');
        else puts("No");
    }
    return 0;
}

【刷題】BZOJ 4998 星球聯盟