二分图 /【模板】线段树分治

XVI.二分图 /【模板】线段树分治

本题有两种做法。一是所谓的“正解”线段树分治,复杂度\(O(n\log n\log k)\)。思路比较简单,敲起来也简单,就是复杂度不太优秀。

代码:

#include<bits/stdc++.h>
using namespace std;
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
int n,m,lim,cnt,dsu[200100],sz[200100];
int find(int x){
	return dsu[x]==x?x:find(dsu[x]);
}
struct opt{
	int u,v,su,sv;
	opt(int a=0,int b=0,int c=0,int d=0){u=a,v=b,su=c,sv=d;}
};
stack<opt>s;
int merge(int x,int y){
	x=find(x),y=find(y);
	if(x==y)return 0;
	s.push(opt(x,y,sz[x],sz[y]));
	if(sz[x]<sz[y])dsu[x]=y,sz[y]+=sz[x];
	else dsu[y]=x,sz[x]+=sz[y];
	return 1;
}
void Pop(){
	dsu[s.top().u]=s.top().u,dsu[s.top().v]=s.top().v,sz[s.top().u]=s.top().su,sz[s.top().v]=s.top().sv,s.pop();
}
bool link(int x,int y){
	int tot=merge(x+n,y)+merge(x,y+n);
	if(find(x)!=find(x+n)&&find(y)!=find(y+n))return true;
	while(tot--)Pop();
	return false;
}
vector<pair<int,int> >v[400100];
void modify(int x,int l,int r,int L,int R,int f,int g){
	if(l>R||r<L)return;
	if(L<=l&&r<=R){v[x].push_back(make_pair(f,g));return;}
	modify(lson,l,mid,L,R,f,g),modify(rson,mid+1,r,L,R,f,g);
}
void dfs(int x,int l,int r){
	int res=0,len=s.size();
	for(int i=0,tmp;i<v[x].size();i++){
		tmp=link(v[x][i].first,v[x][i].second);
		res+=!tmp;
	}
	cnt+=res;
	if(l==r){puts(cnt?"No":"Yes"),cnt-=res;return;}
	dfs(lson,l,mid),dfs(rson,mid+1,r);
	while(s.size()>len)Pop();
	cnt-=res;
}
int main(){
	scanf("%d%d%d",&n,&m,&lim);
	for(int i=1;i<=2*n;i++)dsu[i]=i,sz[i]=1;
	for(int i=1,x,y,l,r;i<=m;i++){
		scanf("%d%d%d%d",&x,&y,&l,&r),l++;
		if(l<=r)modify(1,1,lim,l,r,x,y);
	}
	dfs(1,1,lim);
	return 0;
}

二是所谓的“暴力解法”,但是复杂度反而更优,为\(O(n\log n)\)的LCT。

具体想法是,我们维护原图关于删除时间的最大生成森林。

当加入一条新边构成环时:

我们在LCT中提取出来新边的路径。如果这条新边构成奇环(即这条路径的size为奇)的话,则直到这个奇环的删除时间最小的那条边被删除为止,这张图都不会是二分图。

正因如此,我们才会贪心地维护最大生成树,因为最大生成树就意味着构成的奇环是正确的,保证直到环上第一条边删去前,它都不会是二分图。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,lim,res[100100];
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct LCT{
	int fa,ch[2],mn,val,sz;
	bool rev;
}t[300100];
inline int identify(int x){
	if(x==t[t[x].fa].ch[0])return 0;
	if(x==t[t[x].fa].ch[1])return 1;
	return -1;
}
inline void pushup(int x){
	t[x].mn=x;
	t[x].sz=(x<=n);
	if(lson){
		if(t[t[x].mn].val>t[t[lson].mn].val)t[x].mn=t[lson].mn;
		t[x].sz+=t[lson].sz;
	}
	if(rson){
		if(t[t[x].mn].val>t[t[rson].mn].val)t[x].mn=t[rson].mn;
		t[x].sz+=t[rson].sz;
	}
}
inline void REV(int x){
	t[x].rev^=1,swap(lson,rson);
}
inline void pushdown(int x){
	if(!t[x].rev)return;
	if(lson)REV(lson);
	if(rson)REV(rson);
	t[x].rev=0;
}
inline void rotate(int x){
	register int y=t[x].fa;
	register int z=t[y].fa;
	register int dirx=identify(x);
	register int diry=identify(y);
	register int b=t[x].ch[!dirx];
	if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
	if(b)t[b].fa=y;t[y].ch[dirx]=b;
	t[y].fa=x,t[x].ch[!dirx]=y;
	pushup(y),pushup(x);
}
inline void pushall(int x){
	if(identify(x)!=-1)pushall(t[x].fa);
	pushdown(x);
}
inline void splay(int x){
	pushall(x);
	while(identify(x)!=-1){
		register int fa=t[x].fa;
		if(identify(fa)==-1)rotate(x);
		else if(identify(x)==identify(fa))rotate(fa),rotate(x);
		else rotate(x),rotate(x);
	}
}
inline void access(int x){
	for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y,pushup(x);
}
inline void makeroot(int x){
	access(x),splay(x),REV(x);
}
inline int findroot(int x){
	access(x),splay(x);
	pushdown(x);
	while(lson)x=lson,pushdown(x);
	splay(x);
	return x;
}
inline void split(int x,int y){
	makeroot(x),access(y),splay(y);
}
inline void link(int x,int y){
	makeroot(x),t[x].fa=y;
}
inline void cut(int x,int y){
	split(x,y),t[y].ch[0]=t[x].fa=0,pushup(y);
}
pair<int,int>p[200100];
vector<int>stt[100100],fin[100100];
bool on[200100];
int main(){
	scanf("%d%d%d",&n,&m,&lim);
	for(int i=1;i<=n+m;i++)t[i].mn=i;
	for(int i=1;i<=n;i++)t[i].val=0x3f3f3f3f,t[i].sz=1;
	for(int i=1,a,b,c,d;i<=m;i++){
		scanf("%d%d%d%d",&a,&b,&c,&d),stt[c].push_back(i),fin[d].push_back(i);
		t[i+n].val=d;
		p[i]=make_pair(a,b);
	}
	for(int i=0;i<lim;i++){
		for(int j=0;j<stt[i].size();j++){
			int id=stt[i][j];
			if(findroot(p[id].first)!=findroot(p[id].second))link(p[id].first,id+n),link(p[id].second,id+n),on[id]=true;
			else{
				split(p[id].first,p[id].second);
				int tmp=t[p[id].second].mn;
				if(t[p[id].second].sz&1)res[i]++,res[min(t[tmp].val,t[id+n].val)]--;
				if(p[id].first==p[id].second)continue;
				if(t[tmp].val>=t[id+n].val)continue;
				on[tmp-n]=false,cut(p[tmp-n].first,tmp),cut(p[tmp-n].second,tmp);
				on[id]=true,link(p[id].first,id+n),link(p[id].second,id+n);
			}
		}
		for(int j=0;j<fin[i].size();j++){
			int id=fin[i][j];
			if(on[id])cut(p[id].first,id+n),cut(p[id].second,id+n);
		}
		if(i)res[i]+=res[i-1];
		puts(res[i]?"No":"Yes");
	}
	return 0;
}

posted @ 2021-03-31 16:19  Troverld  阅读(70)  评论(0编辑  收藏  举报