[BZOJ4025]二分图
[BZOJ4025]二分图
试题描述
神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。
输入
输入数据的第一行是三个整数n,m,T。
第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。
输出
输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。
输入示例
3 3 3 1 2 0 2 2 3 0 3 1 3 1 2
输出示例
Yes
No
Yes
数据规模及约定
n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。
题解
一个图是二分图的充要条件就是不存在奇环。
那么我们动态树维护一下删除时间最大生成树。每次加入一条边,如果形成奇环,那么计数器 +1,然后再环中最小权值(权值即删除时间)的时刻计数器 -1;那么删除时如果是树边就在 LCT 上删去,否则跳过。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> #include <vector> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 100010 #define maxm 200010 #define maxnode 300010 #define oo 2147483647 struct Node { int delt, mn, v, siz; bool rev; Node(): rev(0) {} Node(int _, int __): delt(_), v(__) {} } ns[maxnode]; int fa[maxnode], ch[maxnode][2], S[maxnode], top; bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); } void maintain(int o) { ns[o].mn = o; ns[o].siz = ns[o].v; for(int i = 0; i < 2; i++) if(ch[o][i]) { int tmp = ns[ch[o][i]].mn, &me = ns[o].mn; if(ns[tmp].delt < ns[me].delt) me = tmp; ns[o].siz += ns[ch[o][i]].siz; } return ; } void pushdown(int o) { if(!ns[o].rev) return ; swap(ch[o][0], ch[o][1]); for(int i = 0; i < 2; i++) if(ch[o][i]) ns[ch[o][i]].rev ^= 1; ns[o].rev = 0; return ; } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(!isrt(y)) ch[z][ch[z][1]==y] = u; if(ch[y][1] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); maintain(u); return ; } void splay(int u) { int t = u; S[top = 1] = t; while(!isrt(t)) S[++top] = fa[t], t = fa[t]; while(top) pushdown(S[top--]); while(!isrt(u)) { int y = fa[u], z = fa[y]; if(!isrt(y)) { if(ch[y][0] == u ^ ch[z][0] == y) rotate(u); else rotate(y); } rotate(u); } return ; } void access(int u) { splay(u); ch[u][1] = 0; maintain(u); while(fa[u]) splay(fa[u]), ch[fa[u]][1] = u, maintain(fa[u]), splay(u); return ; } void makeroot(int u) { access(u); ns[u].rev ^= 1; return ; } void link(int a, int b) { makeroot(b); fa[b] = a; return ; } void cut(int a, int b) { makeroot(a); access(b); if(fa[a] != b) return ; ch[b][0] = fa[a] = 0; maintain(b); return ; } int _mn, _siz; void query(int a, int b) { makeroot(a); access(b); _mn = ns[b].mn; _siz = ns[b].siz; return ; } bool same(int a, int b) { makeroot(a); access(b); while(!isrt(a)) a = fa[a]; return a == b; } struct Edge { int u, v, st, en; Edge() {} Edge(int _1, int _2, int _3, int _4): u(_1), v(_2), st(_3), en(_4) {} bool operator < (const Edge& t) const { return st != t.st ? st < t.st : en < t.en; } } es[maxm]; vector <int> dele[maxn]; int del[maxn]; int main() { int n = read(), m = read(), T = read(); for(int i = 1; i <= n; i++) ns[i] = Node(oo, 0), maintain(i); for(int i = 1; i <= m; i++) { int u = read(), v = read(), a = read(), b = read(); es[i] = Edge(u, v, a, b); } sort(es + 1, es + m + 1); for(int i = 1; i <= m; i++) if(es[i].st != es[i].en) dele[es[i].en].push_back(i); int tot = 0; for(int t = 0, i = 1; t < T; t++) { tot -= del[t]; for(int j = 0; j < dele[t].size(); j++) { int e = dele[t][j]; cut(es[e].u, e + n); cut(e + n, es[e].v); } for(; i <= m && t >= es[i].st; i++) { if(es[i].st == es[i].en) continue; int u = es[i].u, v = es[i].v; ns[i+n] = Node(es[i].en, 1); if(same(u, v)) { query(u, v); if(_siz & 1) ; else tot++, del[min(ns[_mn].delt,es[i].en)]++; if(ns[_mn].delt < es[i].en) { cut(es[_mn-n].u, _mn); cut(_mn, es[_mn-n].v); link(u, i + n); link(i + n, v); } } else { link(u, i + n); link(i + n, v); } } puts(tot ? "No" : "Yes"); } return 0; }