Description
给出一张n个点m条边的图,有k种颜色,给出q次操作,每次操作形如“将第i条边染成颜色c”
如果某一次操作之后会使得对于颜色c,只考虑颜色c的边,原图不是一个二分图,那么这次操作无效(即不会进行染色)
求每次操作是否成功。
n,m,q<=5*1e5,k<=20
Solution
首先这是一个动态二分图的问题,可以直接通过并查集+分治做到两个log
具体来说每条边有出现时间区间,按时间分治直接加边删边。
这里的删边都是删去刚刚加入的边,可以通过并查集按秩合并支持撤销。
然后这道题的问题是我们不知道每条边的实际存在时间区间,怎么办?
我们可以把每条边当做存在然后扔进分治结构,有序便利每一个子节点,如果当前操作是有效的,那么就把当前边的颜色更新。
然后我们把这条边的下一个时间区间扔进分治结构。
复杂度是相同的。
Code
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
const int N=5*1e5+5,D=55;
int n,m,k,id,c,q,lst[N],x[N],y[N],stack[N<<1],col[N<<1],color[N],tot;
struct node{int r,c,e;}p[N];
struct DSU{
int f[N],rank[N],val[N];
int get(int x) {return f[x]?get(f[x]):x;}
int find(int x) {return f[x]?(val[x]^find(f[x])):0;}
void Union(int c,int ax,int ay) {
int x=get(ax),y=get(ay);
if (x==y) return;
if (rank[x]<rank[y]) {
stack[++tot]=x;col[tot]=c;
val[x]=find(ax)^find(ay)^1;f[x]=y;
} else {
stack[++tot]=y;col[tot]=c;
val[y]=find(ax)^find(ay)^1;f[y]=x;
if (rank[x]==rank[y]) {
rank[x]++;
stack[++tot]=-x;col[tot]=c;
}
}
}
}d[D];
void remove(int now) {
for(;tot>now;tot--)
if (stack[tot]>0) d[col[tot]].f[stack[tot]]=0;
else d[col[tot]].rank[-stack[tot]]--;
}
vector< pair<int,int> > que[N<<2];
void insert(int v,int l,int r,int x,int y,pair<int,int> s) {
if (x>y) return;
if (l==x&&r==y) {que[v].push_back(s);return;}
int mid=l+r>>1;
if (y<=mid) insert(v<<1,l,mid,x,y,s);
else if (x>mid) insert(v<<1|1,mid+1,r,x,y,s);
else insert(v<<1,l,mid,x,mid,s),insert(v<<1|1,mid+1,r,mid+1,y,s);
}
void solve(int v,int l,int r) {
int now=tot;
for(int i=0;i<que[v].size();i++) {
int c=que[v][i].first,e=que[v][i].second;
d[c].Union(c,x[e],y[e]);
}
if (l==r) {
int ax=x[p[l].e],ay=y[p[l].e],c=p[l].c;
if (d[c].get(ax)!=d[c].get(ay)||d[c].find(ax)!=d[c].find(ay)) {
puts("YES");
color[p[l].e]=p[l].c;
} else puts("NO");
insert(1,1,q,l+1,p[l].r,pair<int,int>(color[p[l].e],p[l].e));
remove(now);
return;
}
int mid=l+r>>1;
solve(v<<1,l,mid);
solve(v<<1|1,mid+1,r);
remove(now);
}
int main() {
n=read();m=read();k=read();q=read();
fo(i,1,m) x[i]=read(),y[i]=read();
fo(i,1,q) {
id=read();c=read();
if (lst[id]) p[lst[id]].r=i-1;
p[i].e=id;p[i].c=c;p[i].r=q;
lst[id]=i;
}
solve(1,1,q);
return 0;
}