[ CDQ分治 并查集 ][ AHOI2013 ] BZOJ3237

来源:互联网 发布:下载图片编辑软件 编辑:程序博客网 时间:2024/05/18 01:00

分治到区间 [l,r] 时,将 [mid+1,r] 中不在 [l,mid] 出现的边加入,然后分治左区间,右区间类似。这样就能保证分治到一个区间时所有不在区间中的边都加入了。并查集维护图的连通就好了。

#include<bits/stdc++.h>using namespace std;inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void Read(int& x){    char c=nc();    for(;c<'0'||c>'9';c=nc());    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());}#define N 100010#define M 200010int a[N][5],num[N];int k,n,m,p;int f[N],s[M*50],t[M*50],top;int u[M],v[M],Q,c[M];bool Ans[N];inline int Find(int x){    if(f[x]==x)return x;    int y=Find(f[x]);    if(y!=f[x])s[++top]=x,t[top]=f[x];    return f[x]=y;}inline void Solve(int l,int r){    int k=top;    if(l==r){        bool fl=0;        for(int i=1;i<=num[l];i++){            int tmp=a[l][i];            int x=Find(u[tmp]),y=Find(v[tmp]);            if(x!=y){                fl=1;                break;            }        }        while(top!=k)f[s[top]]=t[top],top--;        Ans[l]=fl;        return;    }    int Mid=l+r>>1;    for(int i=Mid+1;i<=r;i++)        for(int j=1;j<=num[i];j++){            int tmp=a[i][j];            if(!(--c[tmp])){                int x=Find(u[tmp]),y=Find(v[tmp]);                if(x!=y){                    s[++top]=x;t[top]=f[x];f[x]=y;                }            }        }    Solve(l,Mid);    for(int i=Mid+1;i<=r;i++)for(int j=1;j<=num[i];j++)c[a[i][j]]++;    while(top!=k)f[s[top]]=t[top],top--;    for(int i=l;i<=Mid;i++)        for(int j=1;j<=num[i];j++){            int tmp=a[i][j];            if(!(--c[tmp])){                int x=Find(u[tmp]),y=Find(v[tmp]);                if(x!=y){                    s[++top]=x;t[top]=f[x];f[x]=y;                }            }        }    Solve(Mid+1,r);    for(int i=l;i<=Mid;i++)for(int j=1;j<=num[i];j++)c[a[i][j]]++;    while(top!=k)f[s[top]]=t[top],top--;}int main(){    Read(n);Read(m);    for(int i=1;i<=m;i++)Read(u[i]),Read(v[i]);    Read(Q);    for(int i=1;i<=Q;i++){        Read(num[i]);        for(int j=1;j<=num[i];j++)Read(a[i][j]),c[a[i][j]]++;    }    for(int i=1;i<=n;i++)f[i]=i;    for(int i=1;i<=m;i++)    if(!c[i]){        int x=Find(u[i]),y=Find(v[i]);        if(x!=y)f[x]=y;    }    Solve(1,Q);    for(int i=1;i<=Q;i++)    if(!Ans[i])puts("Connected");else puts("Disconnected");    return 0;}