P5787 【模板】线段树分治

题目描述

神犇有一个 \(n\) 个节点的图。

因为神犇是神犇,所以在 \(k\) 时间内有 \(m\) 条边会出现后消失。

神犇要求出每一时间段内这个图是否是二分图。

这么简单的问题神犇当然会做了,于是他想考考你。

原 BZOJ4025。

输入格式

第一行三个整数 \(n,m,k\)。

接下来 \(m\) 行,每行四个整数 \(x,y,l,r\),表示有一条连接 \(x,y\) 的边在 \(l\) 时刻出现 \(r\) 时刻消失。

输出格式

\(k\) 行,第 \(i\) 行一个字符串 Yes 或 No,表示在第 \(i\) 时间段内这个图是否是二分图。


#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+5,M=4e5+5;
inline int read(){
	int x=0; char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
	return x;
}
int fa[N],rnk[N];
struct FUCK{
	int *x,y,*u,v;
};
stack<FUCK>st;
inline int get(int x){
	while(x^fa[x])x=fa[x];
	return x;
}
inline void merge(int x,int y){
	x=get(x),y=get(y);
	if(x==y)return;
	if(rnk[x]>rnk[y])swap(x,y);
	st.push((FUCK){fa+x,fa[x],rnk+y,rnk[y]});
	fa[x]=y; rnk[y]+=(rnk[x]==rnk[y]);
}
inline void undo(){
	*st.top().x=st.top().y;
	*st.top().u=st.top().v;
	st.pop();
}
#define mid ((l+r)>>1)
#define ls p<<1
#define rs p<<1|1
struct node{
	int u,v;
};
vector<node>vec[M];
void update(int p,int l,int r,int L,int R,node d){
	if(L<=l&&r<=R){ vec[p].push_back(d); return; }
	if(L<=mid)update(ls,l,mid,L,R,d);
	if(R>mid)update(rs,mid+1,r,L,R,d);
}
int n,m,k;
inline bool insert(int u,int v){
	merge(u,v+n),merge(v,u+n);
	return (get(u)==get(u+n)||get(v)==get(v+n));
}
void query(int p,int l,int r,bool op){
	for(int i=0;i<vec[p].size();i++)op|=insert(vec[p][i].u,vec[p][i].v);
	if(l==r){op?puts("No"):puts("Yes"); return;}
	int sum=st.size();
	query(ls,l,mid,op);
	while(st.size()>sum)undo();
	query(rs,mid+1,r,op);
}
signed main(){
	n=read(),m=read(),k=read();
	for(int i=1;i<=2*n;i++)fa[i]=i,rnk[i]=0;
	for(int i=1,x,y,l,r;i<=m;i++){
		x=read(),y=read(),l=read()+1,r=read();
		update(1,1,k,l,r,(node){x,y});
	}
	query(1,1,k,0);
}
上一篇:最小生成树


下一篇:【二刷随笔】剑指 Offer 37. 序列化二叉树 / leetcode 297,BFS,超详细解题记录!