这种问题,可以很套路的用线段树分治+可回退并查集解决。对每种颜色维护一个可回退并查集,至于二分图的判定,将每条造成奇环的边打个标记就好了,回退的时候撤销一个标记,看一下是否存在标记就行了。
不过这题比较恶心的地方是某条边在某个时间的颜色不是一开始已知的,这个也不难解决,我们递归到叶子节点的时候判断一下是否能修改成功,然后再对下一段时间插入正确的颜色就好了。
时间复杂度
O
(
n
k
+
m
log
2
n
)
\mathcal O(nk+m\log^2n)
O(nk+mlog2n),因为要支持回退,所以不能路径压缩。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <utility>
#define FR first
#define SE second
#define last last2
using namespace std;
struct SETS;
typedef pair<SETS*,int> pr1;
typedef pair<int,int> pr2;
pr1 st[2000000];
int top;
struct SETS {
int fa[500005];
char rank[500005],d[500005];
int find_father(int x) {
return (fa[x]==x)?x:find_father(fa[x]);
}
int find_dis(int x) {
return (fa[x]==x)?0:d[x]^find_dis(fa[x]);
}
void merge(int x,int y) {
int fx=find_father(x),fy=find_father(y);
if (fx==fy) return;
if (rank[fx]>rank[fy]) {
swap(x,y);
swap(fx,fy);
}
if (rank[fx]==rank[fy]) {
rank[fy]++;
st[++top]=pr1(this,-fy);
}
d[fx]=find_dis(x)^find_dis(y)^1;
fa[fx]=fy;
st[++top]=pr1(this,fx);
}
void init(int n) {
for(int i=1;i<=n;i++) fa[i]=i;
}
} s[51];
void ret(int last) {
while (top>last) {
pr1 p=st[top--];
if (p.SE<0) (*p.FR).rank[-p.SE]--;
else (*p.FR).fa[p.SE]=p.SE;
}
}
struct Edge {
int s,t;
Edge() {}
Edge(int a,int b):s(a),t(b) {}
};
Edge e[500005];
vector<pr1> v[2000000];
void update(int l,int r,int o,int lx,int rx,pr1 now) {
if (l>=lx&&r<=rx) v[o].push_back(now);
else {
int m=((l+r)>>1);
if (m>=lx) update(l,m,o*2,lx,rx,now);
if (m<rx) update(m+1,r,o*2+1,lx,rx,now);
}
}
pr1 q[500005];
bool ok[500005];
queue <int> mq[500005];
SETS* col[500005];
int n,m,k,que;
void solve(int l,int r,int o) {
int last=top;
for(int i=0;i<v[o].size();i++)
(*v[o][i].FR).merge(e[v[o][i].SE].s,e[v[o][i].SE].t);
if (l==r) {
SETS *d=q[l].FR;
int x=e[q[l].SE].s,y=e[q[l].SE].t;
if ((*d).find_father(x)!=(*d).find_father(y)||(*d).find_dis(x)^(*d).find_dis(y)) {
puts("YES");
col[q[l].SE]=d;
ok[q[l].SE]=true;
}
else puts("NO");
mq[q[l].SE].pop();
if (ok[q[l].SE]&&l<que) update(1,que,1,l+1,mq[q[l].SE].front(),pr1(col[q[l].SE],q[l].SE));
}
else {
int m=((l+r)>>1);
solve(l,m,o*2);
solve(m+1,r,o*2+1);
}
ret(last);
}
int main() {
scanf("%d%d%d%d",&n,&m,&k,&que);
for(int i=1;i<=k;i++) s[i].init(n);
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[i]=Edge(x,y);
}
for(int i=1;i<=que;i++) {
int x,y;
scanf("%d%d",&x,&y);
q[i]=pr1(&s[y],x);
mq[x].push(i);
}
for(int i=1;i<=m;i++) mq[i].push(que);
solve(1,que,1);
return 0;
}