对于一条边
i
i
i,它存在的时间区间为:
[
s
t
a
r
t
i
,
e
n
d
i
−
1
]
[start_i,end_i-1]
[starti,endi−1]
把
[
s
t
a
r
t
i
,
e
n
d
i
−
1
]
[start_i,end_i-1]
[starti,endi−1] 区间拆成线段树上的
O
(
log
T
)
O(\log T)
O(logT) 个区间
并且把边
i
i
i 丢进这些区间的边集
然后把整棵线段树
d
f
s
dfs
dfs 一遍
d
f
s
dfs
dfs 到区间
[
l
,
r
]
[l,r]
[l,r] 时,并查集维护的就是
[
l
,
r
]
[l,r]
[l,r] 这段时间都存在的边,所组成的二分图
如果把二分图黑白染色,那么要保证同一个连通块中,同色的点处于同一并查集
由于距离最近的两个同色点通过异色点间接相连
把每个点
x
x
x 拆成
x
x
x 和
x
+
n
x+n
x+n
合并
x
,
y
x,y
x,y 即合并
(
x
,
y
+
n
)
(x,y+n)
(x,y+n),
(
y
,
x
+
n
)
(y,x+n)
(y,x+n)
如果合并
x
,
y
x,y
x,y 时发现
x
,
y
x,y
x,y 已经处于同一连通块,那么它就不是二分图
具体地,记过程
d
f
s
(
l
,
r
,
p
,
o
p
t
)
dfs(l,r,p,opt)
dfs(l,r,p,opt) 表示
d
f
s
dfs
dfs 到区间
[
l
,
r
]
[l,r]
[l,r],此区间编号为
p
p
p,
o
p
t
opt
opt表示在加入
p
p
p 的边集之前,是不是二分图
初始时
o
p
t
=
1
opt=1
opt=1
d
f
s
dfs
dfs 到
[
l
,
r
]
[l,r]
[l,r] 时,把
p
p
p 的边集加到并查集里去,加边过程中如果发现不是二分图了,就把
o
p
t
=
0
opt=0
opt=0
然后
d
f
s
(
l
,
m
i
d
,
l
s
o
n
[
p
]
,
o
p
t
)
,
d
f
s
(
m
i
d
+
1
,
r
,
r
s
o
n
[
p
]
,
o
p
t
)
dfs(l,mid,lson[p],opt),dfs(mid + 1,r,rson[p],opt)
dfs(l,mid,lson[p],opt),dfs(mid+1,r,rson[p],opt)
d
f
s
dfs
dfs 到叶子的时候,就可以根据
o
p
t
opt
opt,得到时刻
l
l
l 的答案了
回溯时要清掉
p
p
p 的边集
所以要用可持久化并查集,即不能路径压缩
为了保证时间复杂度采用启发式合并,即每次把
s
z
e
sze
sze(或
d
e
p
dep
dep) 小的合并到大的
Code
#include<bits/stdc++.h>usingnamespace std;#define p2 p << 1#define p3 p << 1 | 1template<classt>inlinevoidread(t & res){char ch;while(ch =getchar(),!isdigit(ch));
res = ch ^48;while(ch =getchar(),isdigit(ch))
res = res *10+(ch ^48);}constint e =2e6+5;struct point
{int x, y;}a[e];
vector<int>g[e];int stk[e], top, n, m, q, f[e], sze[e];bool ans[e], pd;inlineintfind(int x){return!f[x]? x :find(f[x]);}inlinevoidmerge(int x,int y){
stk[++top]=0;
x =find(x);
y =find(y);if(x == y)return;if(sze[x]> sze[y])swap(x, y);
sze[y]+= sze[x];
f[x]= y;
stk[top]= x;}inlinevoiddel(){int x = stk[top--];if(!x)return;
sze[f[x]]-= sze[x];
f[x]=0;}inlinevoidmodify(int l,int r,int s,int t,int v,int p){if(l == s && r == t){
g[p].push_back(v);return;}int mid = l + r >>1;if(t <= mid)modify(l, mid, s, t, v, p2);elseif(s > mid)modify(mid +1, r, s, t, v, p3);else{modify(l, mid, s, mid, v, p2);modify(mid +1, r, mid +1, t, v, p3);}}inlinevoiddfs(int l,int r,int p,int opt){int i, len = g[p].size();for(i =0; i < len; i++){int j = g[p][i];int x = a[j].x, y = a[j].y;if(find(x)==find(y)) opt =0;merge(x, y + n);merge(x + n, y);}if(l == r){
ans[l]= opt;for(i =0; i < len; i++){del();del();}return;}int mid = l + r >>1;dfs(mid +1, r, p3, opt);dfs(l, mid, p2, opt);for(i =0; i < len; i++){del();del();}}intmain(){read(n);read(m);read(q);int i, l, r;for(i =1; i <=2* n; i++) sze[i]=1;for(i =1; i <= m; i++){read(a[i].x);read(a[i].y);read(l);read(r);
r--;if(l <= r)modify(0, q, l, r, i,1);}dfs(0, q,1,1);for(i =0; i < q; i++)puts(ans[i]?"Yes":"No");return0;}