题目大意
现在有
N
个点,
1.
Ord=1
:读入
u,v
表示连接
u,v
。
2.
Ord=0
:读入
u
表示删除第
对于每次操作,如果当前是一幅二分图则输出
YES
,否则输出
NO
。
N,M≤3∗105
解题思路
我们先考虑没有删除的情况,判断当前的图是不是一个二分图就相当与判断图中有没有奇环。这个可以用并查集集很轻松的维护(直接记录一下当前点与他祖先是否在二分图的一边,每次找父亲的时候更新一下)。
现在增加了删除操作,我们发现在线很难维护(好像用LCT可以做),那么我们就想想离线的做法。我们可以把第
i
个操作设为时间
由于如果并查集加了路径压缩优化后就会丢失中间的信息,所以我们考虑只用按秩合并在 LogN 的时间内维护并查集,然后对于每个 CDQ 分治的每个状态记录下这一层对当前二分图的影响,退出时再恢复就可以了。
程序
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 3e5 + 5;
struct Node {
int u, v, l, r;
Node (int a, int b, int c, int d) {u = a, v = b, l = c, r = d;}
Node () {}
} D[MAXN];
int N, M, tot, Ans[MAXN], Save[MAXN], Cnt, Fa[MAXN], Val[MAXN], Deep[MAXN];
int Get(int u) {return (Fa[u] == u) ? u : Get(Fa[u]);}
int GetVal(int u) {
int Ans = 0;
for (; u != Fa[u]; u = Fa[u]) Ans ^= Val[u];
return Ans;
}
void Back(int tag) {
for (; Cnt != tag; Cnt --) {
if (Save[Cnt] < 0) Deep[-Save[Cnt]] --; else {
Fa[Save[Cnt]] = Save[Cnt];
Val[Save[Cnt]] = 0;
}
}
}
void Push(int u, int v, int val) {
if (Deep[u] > Deep[v]) swap(u, v);
if (Deep[u] == Deep[v]) {
Deep[v] ++;
Save[++ Cnt] = -v;
}
Fa[u] = v, Val[u] = val;
Save[++ Cnt] = u;
}
void Solve(int L, int R, int Num) {
int tag = Cnt;
for (int i = 1; i <= Num; i ++) {
int u = D[i].u, v = D[i].v;
if (D[i].l <= L && D[i].r >= R) {
int fu = Get(u), fv = Get(v);
int Val = GetVal(u) ^ GetVal(v) ^ 1;
if (fu == fv) {
if (Val) {
for (int j = L; j <= R; j ++) printf("NO\n");
Back(tag);
return;
}
}
Push(fu, fv, Val);
swap(D[i --], D[Num --]);
}
}
if (L == R) {
printf("YES\n");
Back(tag);
return;
}
int Mid = (L + R) >> 1, Lim = Num;
for (int i = 1; i <= Lim; i ++)
if (D[i].l > Mid) swap(D[i --], D[Lim --]);
Solve(L, Mid, Lim);
Lim = Num;
for (int i = 1; i <= Lim; i ++)
if (D[i].r <= Mid) swap(D[i --], D[Lim --]);
Solve(Mid + 1, R, Lim);
Back(tag);
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= M; i ++) {
int Ord;
scanf("%d", &Ord);
if (Ord == 1) {
int u, v;
scanf("%d %d\n", &u, &v);
u ++, v ++;
D[++ tot] = Node(u, v, i, N);
} else {
int id;
scanf("%d\n", &id);
D[++ id].r = i - 1;
}
}
for (int i = 1; i <= N; i ++) Fa[i] = i;
Solve(1, M, tot);
}