4025: 二分图
思路:
考虑按时间分治,然后把每条边按影响时间加入相应的区间(类似划分树)。然后考虑把包含每个叶子节点的边连起来,并判断有没有奇环。
由于分治时需要撤回某些并查集的合并操作,所以需要用到可撤销并查集。然后因为要判基环,所以又需要维护每个点到父亲节点的距离\(dp[i]\),
所以需要用到带权并查集。
代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long #define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define pdd pair<double, double> #define mem(a, b) memset(a, b, sizeof(a)) #define debug(x) cerr << #x << " = " << x << "\n"; #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); //head const int N = 1e5 + 5; int n, m, T, u, v, l, r; vector<pii> vc[N<<2]; bool ans[N]; struct UFS { stack<pair<int*, int> > stk; int fa[N], rnk[N], dp[N], c; inline void init(int n) { for (int i = 0; i <= n; ++i) fa[i] = i, rnk[i] = 0, dp[i] = 0; c = 0; } inline int Find(int x) { while(x^fa[x]) x = fa[x]; return x; } inline int Deep(int x) { int res = 0; while(x^fa[x]) res += dp[x], x = fa[x]; return res; } inline void Merge(int x, int y) { int fx = Find(x), fy = Find(y); if(fx == fy) { int dx = Deep(x), dy = Deep(y); if((dx+dy+1)%2) { stk.push(mp(&c, c)); c++; } return ; } if(rnk[fx] <= rnk[fy]) { stk.push(mp(fa+fx, fa[fx])); stk.push(mp(dp+fx, dp[fx])); dp[fx] = dp[y]-dp[x]+1; fa[fx] = fy; if(rnk[fx] == rnk[fy]) { stk.push(mp(rnk+fy, rnk[fy])); rnk[fy]++; } } else { stk.push(mp(fa+fy, fa[fy])); stk.push(mp(dp+fy, dp[fy])); dp[fy] = dp[x]-dp[y]+1; fa[fy] = fx; } } inline void Undo() { *stk.top().fi = stk.top().se; stk.pop(); } }ufs; void update(int L, int R, pii p, int rt, int l, int r) { if(L <= l && r <= R) return vc[rt].pb(p), void(); int m = (l+r) >> 1; if(L <= m)update(L, R, p, ls); if(R > m) update(L, R, p, rs); } void dfs(int rt, int l, int r) { for (int i = 0; i < vc[rt].size();++i) ufs.Merge(vc[rt][i].fi, vc[rt][i].se); if(l == r) { if(ufs.c) printf("No\n"); else printf("Yes\n"); return ; } int sz = ufs.stk.size(); int m = (l+r) >> 1; dfs(ls); while(ufs.stk.size() > sz) ufs.Undo(); dfs(rs); while(ufs.stk.size() > sz) ufs.Undo(); } int main() { scanf("%d %d %d", &n, &m, &T); for (int i = 1; i <= m; ++i) scanf("%d %d %d %d", &u, &v, &l, &r), update(l+1, r, {u, v}, 1, 1, T); ufs.init(n); dfs(1, 1, T); return 0; }