bzoj4025 二分图
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4025
【题解】
考虑对时间分治,用可撤回的启发式合并并查集来维护连通性。
二分图的条件是没有奇环,用并查集判即可。
对于时间区间[l,r],如果边在这期间都存在,那么就加入并查集,对于剩下的边分类,并且分治下去做。
对于每条边,在log个区间表示出来了,需要进行判断,启发式合并的getf是log的,所以复杂度为O(nlog^2n)
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 1e6 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m, T; struct edge { int u, v, st, ed; edge() {} edge(int u, int v, int st, int ed) : u(u), v(v), st(st), ed(ed) {} }e[M]; int st[N]; int stn = 0; struct us { int n, fa[M], rk[M], dis[M]; inline void set(int _n) { n = _n; for (int i=1; i<=n; ++i) fa[i] = i, rk[i] = 1, dis[i] = 0; } inline int getf(int x) { return fa[x] == x ? x : getf(fa[x]); } inline int getdis(int x) { int d = 0; while(fa[x] != x) d += dis[x], x = fa[x]; return d; } inline void un(int fu, int fv, int d) { if(rk[fu] > rk[fv]) swap(fu, fv); if(rk[fu] == rk[fv]) rk[fv] ++, st[++stn] = -fv; fa[fu] = fv; dis[fu] = d; ++stn; st[stn] = fu; } inline void re() { int x = st[stn]; --stn; if(x < 0) --rk[-x]; else dis[x] = 0, fa[x] = x; } }E; bool ans[M]; inline void solve(int tl, int tr, int er) { // printf("l = %d, r = %d\n", tl, tr); int cur_stn = stn; for (int i=1; i<=er; ++i) { if(!(e[i].st <= tl && tr <= e[i].ed)) continue; // printf("doing: (%d, %d, %d, %d)\n", e[i].u, e[i].v, e[i].st, e[i].ed); int fu = E.getf(e[i].u), fv = E.getf(e[i].v); int du = E.getdis(e[i].u), dv = E.getdis(e[i].v); if(fu != fv) E.un(fu, fv, du+dv+1); else { // printf("%d %d fa = %d %d %d\n", e[i].u, e[i].v, E.fa[1], du, dv); if((du+dv+1)&1) { // puts("Proves odd"); while(stn != cur_stn) E.re(); return ; } } swap(e[i], e[er]); --er; --i; } if(tl == tr) { ans[tl] = 1; while(stn != cur_stn) E.re(); return ; } int mid = tl+tr >> 1; int ER = er; for (int i=1; i<=er; ++i) if(e[i].st > mid) { swap(e[i], e[er]); --er; --i; } solve(tl, mid, er); er = ER; for (int i=1; i<=er; ++i) { if(e[i].ed <= mid) { swap(e[i], e[er]); --er; --i; } } solve(mid+1, tr, er); while(stn != cur_stn) E.re(); } int main() { cin >> n >> m >> T; E.set(n); int en = 0; for (int i=1, u, v, sta, end; i<=m; ++i) { scanf("%d%d%d%d", &u, &v, &sta, &end); ++sta; if(sta>end) continue; e[++en] = edge(u, v, sta, end); } m = en; solve(1, T, m); for (int i=1; i<=T; ++i) puts(ans[i] ? "Yes" : "No"); return 0; }