一条边有存在的时间 [start,end] ,问每个时刻该时图是不是二分图。
是二分图就不存在奇环,考虑并查集维护最大生成树,是否是奇环也很好判断了,两点间距离就是dis[a]+dis[b]-2*dis[LCA],由于我们只关心奇偶性,因此把加减法换成xor也是可以的,然后就变成了dis[a]^dis[b]了,加上非树边就是环了。
那么我们就考虑扫一遍时间,然后到了对应时间就加入边、删除边,维护连通性,但是并查集不资瓷解绑啊?
分治大法好!按时间分治,分治到对应的边,搞一下,然后我们只需要回退并查集到之前的版本就可以了;然后剩下的边就交给下一层处理。
另外考虑不用并查集的情况,我们可以LCT维护最大生成树,还是维护两点间xor值,如果不连通还是一样的添加边或删除边,如果形成了环,而且是奇环,加到集合中,删除的时候,如果是非树边,从集合中删除。那么集合空就是二分图。
代码%%%Po神
好像分治会比一些写的好的LCT慢。毕竟复杂度摆在这。
#include <cstdio>
#include <vector>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
using namespace std;
const int N = 100005;
int fa[N], rnk[N], c[N], ver, stk[N];
int find(int x) {
for (; x != fa[x]; x = fa[x]);
return x;
}
int dist(int x) {
int ans = 0;
for (; fa[x] && fa[x] != x; x = fa[x]) ans ^= c[x];
return ans;
}
void merge(int x, int y, int z) {
x = find(x); y = find(y);
if (x == y) return;
if (rnk[x] > rnk[y]) swap(x, y);
if (rnk[x] == rnk[y]) ++rnk[y], stk[++ver] = -y;
fa[x] = y; c[x] = z; stk[++ver] = x;
}
void restore(int now) {
for (; ver > now; --ver) {
if (stk[ver] < 0) --rnk[-stk[ver]];
else fa[stk[ver]] = stk[ver], c[stk[ver]] = 0;
}
}
struct Edge {
int x, y, s, t;
Edge(int i = 0, int j = 0, int k = 0, int l = 0): x(i), y(j), s(k), t(l) { }
};
void divide(int l, int r, vector<Edge> &e) {
int i, mid = l + r >> 1, now = ver;
vector<Edge> L, R;
for (vector<Edge>::iterator it = e.begin();
it != e.end(); ++it) {
if (it->s == l && it->t == r) {
int a = find(it->x), b = find(it->y), c = dist(it->x) ^ dist(it->y) ^ 1;
if (a != b) merge(a, b, c);
else if (c & 1) {
FOR(i,l,r) puts("No");
restore(now);
return;
}
} else if (it->t <= mid) L.push_back(*it);
else if (it->s > mid) R.push_back(*it);
else {
L.push_back(Edge(it->x, it->y, it->s, mid));
R.push_back(Edge(it->x, it->y, mid + 1, it->t));
}
}
if (l == r) puts("Yes");
else divide(l, mid, L), divide(mid + 1, r, R);
restore(now);
}
int main() {
int i, n, m, t, a, b, c, d;
vector<Edge> v;
scanf("%d%d%d", &n, &m, &t);
FOR(i,1,n) fa[i] = i;
FOR(i,1,m) {
scanf("%d%d%d%d", &a, &b, &c, &d);
++c; if (c > d) continue;
v.push_back(Edge(a, b, c, d));
}
divide(1, t, v);
return 0;
}