P10778 BZOJ3569 DZY Loves Chinese II 题解
\(\text{P10778 BZOJ3569 DZY Loves Chinese II 题解}\)
由于有强制在线的限制,无法考虑一些奇技淫巧。一般的手段难以维护,于是考虑对于图上问题,先整出一棵生成树来,分为树边和非树边。显然一个环一定由一些树边和一些非树边组成。考虑对于一条被删去的树边,不连通的条件显然是自己本身没有环或是过自己的环中都不只有自己这一条边被删掉。那么考虑对于树边分别考虑,那么就检查过这条边的环上是否清空了所有非树边。转化条件,考虑非树边的话就是非树边两点之间的所有树边会被做贡献,那么可以认为出现不连通情形当且仅当一个树边被删除的同时删除了所有对其做贡献的非树边。无向图检验环相关问题可以考虑线性基来处理。既然已经使用了线性基,不妨使用异或哈希来解决问题。于是对于每条非树边随机赋定一个权值,向上算每个树边的贡献集合也就是将每个非树边的权值异或起来,如果出现一组异或和为 \(0\),也就是无法插入时,图不连通。
代码:
#include <bits/stdc++.h>
#define N 500005
#define M 31
using namespace std;
int n, m;
mt19937 wdz(time(0));
struct Node {
int to, nxt, id;
} e[N << 1];
int head[N], cnt;
void add(int u, int v, int w) {
e[++cnt] = {v, head[u], w};
head[u] = cnt;
}
int hsh[N], hse[N];
void dfs(int x, int fa) {
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if (y == fa) continue;
dfs(y, x);
hse[e[i].id] = hsh[y];
hsh[x] ^= hsh[y];
}
}
int p[M];
int insert(int x) {
for (int i = M - 1; ~i; --i)
if ((x >> i) & 1) {
if (!p[i]) {
p[i] = x;
return 1;
}
x ^= p[i];
}
return 0;
}
int fa[N];
int fnd(int x) {
return x == fa[x] ? x : fa[x] = fnd(fa[x]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
iota(fa + 1, fa + 1 + n, 1);
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
int sx = fnd(x), sy = fnd(y);
if (sx != sy) add(x, y, i), add(y, x, i), fa[sx] = sy;
else {
int p = wdz() % INT_MAX;
hse[i] = p;
hsh[x] ^= p, hsh[y] ^= p;
}
}
dfs(1, 0);
int T, ct = 0;
cin >> T;
while (T--) {
int k, c, fg = 1;
cin >> k;
memset(p, 0, sizeof p);
while (k--) {
cin >> c;
c ^= ct;
fg &= insert(hse[c]);
}
if (fg) cout << "Connected\n";
else cout << "Disconnected\n";
ct += fg;
}
return 0;
}

浙公网安备 33010602011771号