[CF813F]Bipartite Checking

Bipartite Checking

题解

线段树分治的板子题。

根据时间加边与删边,如果直接维护这个图的话明显会T,当然只加边的画不会,但由于会删边,我们每次判图都必须跑一遍这个图,于是就需要O\left(nq),明显会T,于是就要用线段树分治来维护每个时间上的边。

我们建一棵树来维护每个时间的图,从根到叶子的链上构成的图就是叶子这个时间节点的图的状态。每次删边时,就在这条边存在的时间区间上加上这条边。这样就可以维护任意时间点的图,保证我们到任意点时只会有加边的操作,不会去删边。

至于如何判断二分图,我们在点上都是维护了一个只有加边动态图的,如果回溯的话只需要撤销最后加的那一条边。我们用一个带权并查集去维护这个图,而并查集维护的图又一定是一棵树,而加一条边是可以O\left(1 \right )解决的。为了避免卡并查集,还需要按秩合并去保证树高。

插入边时若这条边连接了两棵未连接的树,明显不会有关系,可如果形成了奇环的话那就肯定不是二分图了,而判奇环就只需要维护每个点的深度。

于是,就可以过这题了。

源码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 200005
typedef long long LL;
#define lson rt<<1
#define rson rt<<1|1
typedef pair pii;
template
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template
_T Fabs(_T x){return x<0?-x:x;}
struct edge{int u,v;edge(int U,int V):u(U),v(V){}};
struct piar{int x,y;piar(int X,int Y):x(X),y(Y){}};
int n,q,L[MAXN<<2],R[MAXN<<2],ans[MAXN];
vector tag[MAXN<<2];
map g[MAXN];
int fa[MAXN],siz[MAXN],dis[MAXN];
void build(int rt,int l,int r){
	L[rt]=l;R[rt]=r;if(l==r)return ;int mid=(l+r)>>1;
	build(lson,l,mid);build(rson,mid+1,r);
}
void query(int rt,int l,int r,const edge &E){
	if(L[rt]>r||R[rt] &sta){
	int dx=getdis(x),dy=getdis(y);
	x=findFa(x);y=findFa(y);
	if(x==y)return dx^dy;
	if(siz[x]>siz[y])swap(x,y),swap(dx,dy);
	siz[y]+=siz[x];fa[x]=y;dis[x]=dx^dy^1;
	sta.push(piar(x,y));return 1;
}
void delet(piar p){int x=p.x,y=p.y;siz[y]-=siz[x];dis[fa[x]=x]=0;} 
void dfs(int rt,int fg){
	stack sta;
	for(auto e:tag[rt])fg&=solve(e.u,e.v,sta);
	if(L[rt]==R[rt])ans[L[rt]]=fg;
	else dfs(lson,fg),dfs(rson,fg);
	while(!sta.empty()){delet(sta.top());sta.pop();}
}
signed main(){
	read(n);read(q);build(1,1,q);
	for(int i=1;i<=q;i++){
		int x,y;read(x);read(y);
		if(!g[x][y])g[x][y]=i;
		else query(1,g[x][y],i-1,edge(x,y)),g[x][y]=0;
	}
	for(int i=1;i<=n;i++){
		siz[fa[i]=i]=1;
		for(auto p:g[i])if(p.second>0)
			query(1,p.second,q,edge(i,p.first));
	}
	dfs(1,1);
	for(int i=1;i<=q;i++)puts(ans[i]?"YES":"NO");
	return 0;
}

谢谢!!!

你可能感兴趣的:(#,线段树分治,#,线段树,#,并查集)