bzoj4025
线段树分治+并查集
跟1018很像,但是这里是带权并查集,修改时要注意,因为可回溯并查集不能路径压缩,所以也不能对保存到根路径长度的数组修改,每次连接,我们只对根的距离数组修改,这样不会影响操作结果,因为路径压缩就是把我们要求的d数组在find时把整个路径上的d数组都顺便修改了,这里我们用到哪个就求哪个,所以不会影响结果,
d[b]=d[u]^d[v]^1
所以b的值就应该是d[u]^d[v]^1,d是到跟路径长度的奇偶性,每次du^=d[u]其实就是查询两点之间的路径长度奇偶性
#include<bits/stdc++.h> using namespace std; const int N = 200010; struct dsu { int a, b, fa, sizea, sizeb, da, db; vector<int> dd; dsu(int a = 0, int b = 0, int fa = 0, int sizea = 0, int sizeb = 0, int da = 0, int db = 0) : a(a), b(b), fa(fa), sizea(sizea), sizeb(sizeb) {} } st[N]; int n, m, top, T; int d[N], fa[N], size[N]; vector<pair<int, int> > tree[N << 2]; bool unite(pair<int, int> o) { int u = o.first, v = o.second, du = 0, dv = 0; while(fa[u] != u) { du ^= d[u]; u = fa[u]; } while(fa[v] != v) { dv ^= d[v]; v = fa[v]; } if(size[u] < size[v]) swap(u, v); st[++top] = dsu(u, v, fa[v], size[u], size[v], d[u], d[v]); if(u == v) { if(du == dv) return false; return true; } size[u] += size[v]; d[v] = du ^ dv ^ 1; fa[v] = u; return true; } void del(int now) { while(top != now) { dsu x = st[top]; size[x.a] = x.sizea; size[x.b] = x.sizeb; d[x.a] = x.da; d[x.b] = x.db; fa[x.b] = x.fa; --top; } } void dfs(int l, int r, int x, bool flag) { int now = top; for(int i = 0; i < tree[x].size(); ++i) if(!unite(tree[x][i])) flag = false; if(l == r) { if(flag) puts("Yes"); else puts("No"); del(now); return; } int mid = (l + r) >> 1; dfs(l, mid, x << 1, flag); dfs(mid + 1, r, x << 1 | 1, flag); del(now); } void update(int l, int r, int x, int a, int b, pair<int, int> o) { if(l > b || r < a) return; if(l >= a && r <= b) { tree[x].push_back(o); return; } int mid = (l + r) >> 1; update(l, mid, x << 1, a, b, o); update(mid + 1, r, x << 1 | 1, a, b, o); } int main() { scanf("%d%d%d", &n, &m, &T); for(int i = 1; i <= n; ++i) { fa[i] = i; size[i] = 1; } for(int i = 1; i <= m; ++i) { int u, v, s, t; scanf("%d%d%d%d", &u, &v, &s, &t); update(1, T, 1, s + 1, t, make_pair(u, v)); } dfs(1, T, 1, true); return 0; }