BZOJ3569

http://www.lydsy.com/JudgeOnline/problem.php?id=3569

先dfs出一棵搜索树,对于非树边给它rand一个边权,然后对于树边的边权等于它被覆盖的非树边的异或和

对于删去的k边,若存在非空子集的异或和为0,说明图不连通,这个可以线性基搞搞

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using namespace std;
const int N=500011;
int nxt[N],las[N],to[N],w[N],_w[N];
bool vis[N];
int a[31];
int tot,n,m,q,k,ans,x,y;
inline void add(int x,int y){
    nxt[++tot]=las[x];las[x]=tot;to[tot]=y;
}
inline void dfs1(int now){
    vis[now]=1;
    for(register int e=las[now];e;e=nxt[e])
        if(!vis[to[e]])
            dfs1(to[e]);
        else{
            w[e]=rand();
            _w[to[e]]^=w[e];
            _w[now]^=w[e];
        }
}
inline void dfs2(int now){
    vis[now]=1;
    for(register int e=las[now];e;e=nxt[e])
        if(!vis[to[e]]){
            dfs2(to[e]);
            w[e]^=_w[to[e]];
            _w[now]^=_w[to[e]]; 
        }
}
inline bool check(){
    register int now=0;
    for(register int i=30;~i;--i){
        for(register int j=now+1;j<=k;++j)
            if(a[j]&(1<<i)){
                swap(a[j],a[++now]);
                for(register int l=1;l<=k;++l)
                    if(l!=now&&(a[l]&(1<<i)))
                        a[l]^=a[now];
                break;
            }
    }
    return a[k]?0:1;
}
int main(){
    srand(20011214);    
    scanf("%d%d",&n,&m);
    FOR(i,1,m){
        scanf("%d%d",&x,&y);
        if(x>y)swap(x,y);
        add(x,y);
    }
    dfs1(1);
    FOR(i,1,n)
        vis[i]=0;
    dfs2(1);
    scanf("%d",&q);
    while(q--){
        scanf("%d",&k);
        FOR(i,1,k){
            scanf("%d",&x);
            x^=ans;a[i]=w[x];
        }
        if(check())
            puts("Disconnected");
        else{
            puts("Connected");
            ++ans;
        }
    }
    return 0;
}

  

posted @ 2018-01-05 19:45  Stump  阅读(185)  评论(0编辑  收藏  举报