P10778 DZY Loves Chinese II 题解

题目链接

点击打开链接

题目解法

很人类智慧的题
如果不强制在线的话,直接套一个线段树分治就做完了

先给出做法:拉出原树的一棵生成树,令第 \(i\) 条非树边的权值为 \(2^i\),且其两个端点在树上路径对应的边的权值都异或上 \(2^i\)
一个边集删完之后不连通,当且仅当存在这个边集的子集,其权值异或和 \(=0\)
要证明这个结论的正确性,我们分成两步:

  1. 极小的割一定异或和 \(=0\)
    因为是极小的割,所以一定会分成 \(2\) 个集合 \(S,T\),其中间无边
    考虑一个环上,我们定义只有当 \(S,T\) 切换时,边才会被割
    随便选一个位置断环为链,因为起点和末尾属于同一个集合,所以割边的个数为偶数,异或和一定为 \(0\)
  2. 异或和为 \(0\) 的一定是割
    反证,假设割掉之后依然连通,我们在割掉之后的图上重新拉出一棵生成树
    这个操作其实是把割掉的树边替换成非树边
    这里给出一个结论:新的生成树依然满足树边的权值 \(=\) 经过它的非树边的权值的异或和
    证明可以分类讨论,我懒了
    这说明了什么?新的非树边的权值线性无关,这与异或和 \(=0\) 矛盾

给非树边随机权值做即可,时间复杂度 \(O(m+qk\log V)\)

#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
template<typename T> void read(T &FF){
    FF=0;int RR=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    FF*=RR;
}
const int N=100010,M=500010;
int n,m,q,val[M],sum[N];
vector<pii> G[N];
vector<int> son[N];
mt19937 mrand(chrono::steady_clock::now().time_since_epoch().count());
int mx=(1<<30);
bool vis[N];
int faid[N],dep[N];
void dfs(int u){
    vis[u]=1;
    for(auto [v,id]:G[u]){
        if(!vis[v]) son[u].pb(v),faid[v]=id,dep[v]=dep[u]+1,dfs(v);
        else if(dep[v]>dep[u]){
            val[id]=mrand()%mx;
            sum[u]^=val[id],sum[v]^=val[id];
        }
    }
}
void dfs2(int u){
    for(int v:son[u]) dfs2(v),sum[u]^=sum[v];
    if(u>1) val[faid[u]]=sum[u];
}
int base[30];
bool ins(int x){
    DF(i,29,0) if(x>>i&1){
        if(base[i]) x^=base[i];
        else{ base[i]=x;return 1;}
    }
    return 0;
}
int main(){
    read(n),read(m);
    F(i,1,m){
        int x,y;read(x),read(y);
        G[x].pb({y,i}),G[y].pb({x,i});
    }
    dep[1]=1,dfs(1),dfs2(1);
    read(q);
    int cnt=0;
    while(q--){
        int k;read(k);
        ms(base,0);
        bool fl=1;
        F(i,1,k){
            int x;read(x);x^=cnt;
            if(!ins(val[x])) fl=0;
        }
        if(fl) puts("Connected"),cnt++;
        else puts("Disconnected");
    }
    return 0;
}

posted @ 2024-08-16 14:52  Farmer_D  阅读(11)  评论(0)    收藏  举报