题目描述见链接 .
先考虑如何判断是否 二分图, 可以使用 带权并查集 实现, 具体来说:
加入边 时, 设其祖先分别为 , ,
- , 若 为 奇数, 则直接判断 不为二分图, 否则不将此边加入 .
- , 在并查集中, 我们将 接到 上, 之间的路径长度 奇偶性 为 .
再考虑如何维护边的存在, 使用 线段树分治,
每条边都会有一个出现的时间区间 , 考虑建立下标为 的 线段树 ,
将每条边的时间区间 分成 个区间放在 线段树 的节点中,
然后在 线段树 中 , 在到一个节点时执行当前节点存储的所有加边操作,
- 回溯时 栈序 撤回之前操作 .
- 在向下 过程中, 若已经出现 奇环, 则直接 , 其子树内的答案全部为
No
. - 若顺利到达 叶子节点, 没有出现 奇环, 则该时刻答案为
Yes
.
因为要对 并查集 进行撤回操作, 所以要合并时要 按秩合并 .
- 注意 回溯栈 的数组大小与 线段树 节点 数组大小同阶 .
#include<bits/stdc++.h>
#define reg register
#define pb push_back
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 200005;
int N;
int M;
int Tim;
int F[maxn];
int ds[maxn];
int Rk[maxn];
int Ans[maxn];
struct EDGE{ int u, v; } E[maxn];
struct Stak{ int top; EDGE b[maxn<<2]; } stk;
int Find(int x){ return F[x]==x?x:Find(F[x]); }
int ged(int x){ return F[x]==x?0:ged(F[x])^ds[x]; }
struct Segment_Tree{
struct Node{ int l, r; std::vector<int> b; } T[maxn << 2];
void Build(int k, int l, int r){
T[k].l = l, T[k].r = r;
if(l == r) return ; int mid = l+r >> 1;
Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
}
void Add(int k, const int &ql, const int &qr, const int &id){
int l = T[k].l, r = T[k].r;
if(r < ql || l > qr) return ;
if(ql <= l && r <= qr) return T[k].b.pb(id), void();
Add(k<<1, ql, qr, id), Add(k<<1|1, ql, qr, id);
}
void solve(int k){
int last = stk.top; bool flag = 0;
for(reg int i = T[k].b.size()-1; ~i; i --){
// printf("%d
", T[k].b[i]);
EDGE t = E[T[k].b[i]];
int t1 = Find(t.u), t2 = Find(t.v);
if(Rk[t1] > Rk[t2]) std::swap(t1, t2);
//std::swap(t.u, t.v);
int dsu = ged(t.u), dsv = ged(t.v);
if(t1 == t2){ if(!(dsu^dsv)) flag = 1; continue ; }
F[t1] = t2, ds[t1] = dsu ^ dsv ^ 1;
if(Rk[t1] == Rk[t2]){
Rk[t2] ++;
stk.b[++ stk.top] = (EDGE){ t1, 1 };
}else stk.b[++ stk.top] = (EDGE){ t1, 0 };
}
if(!flag){
if(T[k].l == T[k].r) return Ans[T[k].l]=1, void();
solve(k<<1), solve(k<<1|1);
}
while(1){
if(stk.top == last) break ;
int top = stk.top --;
int x = stk.b[top].u;
ds[x] = 0, Rk[F[x]] -= stk.b[top].v, F[x] = x;
}
}
} seg_t;
int main(){
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
N = read(), M = read(), Tim = read();
seg_t.Build(1, 1, Tim);
for(reg int i = 1; i <= M; i ++){
E[i].u = read(), E[i].v = read();
int l = read() + 1, r = read(); //----------------
seg_t.Add(1, l, r, i);
}
for(reg int i = 1; i <= N; i ++) F[i] = i;
seg_t.solve(1);
for(reg int i = 1; i <= Tim; i ++) puts(Ans[i]?"Yes":"No");
return 0;
}