把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

题面传送门
又是一个自己yy出来的数据结构。
考虑在时间轴上建立线段树。
模仿左偏树那题,把修改拆成\(logn\)个询问。
对于每个节点,用扩展域并查集来维护有没有奇环。然后如果这个区间有奇环那么就直接输出。
但是还有一个问题退出当前节点时要撤销这个点的贡献。
那么可以上按秩合并可持久化并查集即可。
代码实现:

#include<cstdio>
#define l(x) x<<1
#define r(x) x<<1|1
#include<vector>
using namespace std;
int n,m,k,x,y,xs,ys,z,head,fa[200039],w[200039],un,wn,flag;
struct yyy{int x,y,flag;}s[200039];
struct ques{int x,y;}tmp;
vector<ques> f[400039];
inline void get(int x,int y,int xs,int ys,int l,int r,int now){
	if(x<=l&&r<=y){f[now].push_back((ques){xs,ys});return;} 
	int m=l+r>>1; 
	if(x<=m) get(x,y,xs,ys,l,m,l(now));
	if(y>m) get(x,y,xs,ys,m+1,r,r(now));
}
inline int find(int x){return fa[x]==x?x:find(fa[x]);}
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline void merge(int x,int y){
	un=find(x);wn=find(y);
	if(un!=wn){
		if(w[un]<w[wn])swap(un,wn); 
		s[++head]=(yyy){un,wn,w[un]==w[wn]};
		fa[wn]=un;
		if(w[wn]==w[un]) w[un]++;
	}
}
inline void del(){fa[s[head].y]=s[head].y;w[s[head].x]-=s[head].flag;head--;}
inline void find(int l,int r,int now){
	int lasthead=head;flag=0;
	for(int i=0;i<f[now].size();i++){
		tmp=f[now][i];
		un=find(tmp.x);wn=find(tmp.y);
		if(un==wn){
			for(int j=l;j<=r;j++) printf("No\n");
			flag=1;break;
		}
		merge(tmp.x,tmp.y+n);merge(tmp.y,tmp.x+n);
	}
	if(l==r&&!flag) printf("Yes\n");
	else if(!flag){
		int m=l+r>>1;
		find(l,m,l(now));find(m+1,r,r(now));
	}
	while(head!=lasthead) del();
	return;
}
int main(){
	freopen("1.in","r",stdin);
	register int i;
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=2*n;i++) fa[i]=i,w[i]=1;
	for(i=1;i<=m;i++) scanf("%d%d%d%d",&xs,&ys,&x,&y),get(x+1,y,xs,ys,1,k,1);
	find(1,k,1);
}
posted @ 2021-01-14 20:46  275307894a  阅读(80)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end