bzoj3569 DZY Loves Chinese II 线性基

Description


神校XJ之学霸兮,Dzy皇考曰JC。
摄提贞于孟陬兮,惟庚寅Dzy以降。
纷Dzy既有此内美兮,又重之以修能。
遂降临于OI界,欲以神力而凌♂辱众生。

今Dzy有一魞歄图,其上有N座祭坛,又有M条膴蠁边。
时而Dzy狂WA而怒发冲冠,神力外溢,遂有K条膴蠁边灰飞烟灭。
而后俟其日A50题则又令其复原。(可视为立即复原)
然若有祭坛无法相互到达,Dzy之神力便会大减,于是欲知其是否连通。

N≤100000 M≤500000 Q≤50000 1≤K≤15

Solution


记得之前做过这题的sb版,好像是连k都要异或于是离线瞎jb做就行了
据说dfs树对付无向图有奇效,反正dfs一次又不亏是不是

考虑先求出图的dfs树,那么对于一条树边,我们需要删掉树边和所有包含树边的非树边才能使图不连通
我们给每条非树边赋随机权,树边的权则是所有包含它的非树边的权的异或和,那么问题转变为删掉的边的集合中是否存在子集异或和为0
这是一个可以用线性基搞定的东西,直接上就行了

对于非树边的处理可以考虑用树上差分打标记的方式前后dfs两次即可

Code


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))

using namespace std;

const int N=500005;
const int E=1000005;

struct edge {int y,next;} e[E];

int bin[34],val[N],rec[N],tag[N];
int ls[N],edCnt=1;

bool vis[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void dfs1(int now,int fa) {
    vis[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa) continue;
        if (!vis[e[i].y]) dfs1(e[i].y,now);
        else if (!val[i/2]) {
            val[i/2]=rand();
            tag[now]^=val[i/2];
            tag[e[i].y]^=val[i/2];
        }
    }
}

void dfs2(int now,int fa,int u) {
    vis[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa) continue;
        if (vis[e[i].y]) continue;
        val[i/2]=u;
        dfs2(e[i].y,now,u^tag[e[i].y]);
    }
}

int main(void) {
    freopen("data.in","r",stdin);
    srand(20020303);
    bin[0]=1; rep(i,1,31) bin[i]=bin[i-1]*2;
    int n=read(),m=read();
    rep(i,1,m) add_edge(read(),read());
    dfs1(1,0);
    fill(vis,0);
    dfs2(1,0,tag[1]);
    for (int T=read(),lastans=0;T--;) {
        rep(i,0,31) rec[i]=0; bool flag=false;
        for (int s=read();s--;) {
            int x=val[read()^lastans];
            drp(i,31,0) if (x&bin[i]) {
                if (!rec[i]) {
                    rec[i]=x;
                    break;
                } else x^=rec[i];
            }
            flag|=(!x);
        }
        lastans+=!flag;
        if (flag) puts("Disconnected");
        else puts("Connected");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80845390
今日推荐