首页 > 其他分享 >【题解】P5787 二分图 /【模板】线段树分治

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

时间:2024-12-08 20:55:37浏览次数:7  
标签:P5787 int 题解 线段 fa siz 区间 模板 define

二分图最简单的方法是染色法实现,但是扩展域并查集也可以实现,有两个集合 \(S,T\),具体的是相连边的两个点 \(x,y\) 总是在不同的两个集合中,若出现在同一集合中即不是一个二分图。

对于时间段建边考虑用线段树储存,线段树按照时间轴划分,将将对应时间区间的节点储存上当前连边操作,小时间区间总是被大时间区间包含。

大佬的图。

图片

可以看到 \(e_2\) 这个操作在互不相交的对应时间区间上都储存了,我们如何查询呢,我们从大区间依次加边,同时判断合法,如果[l,r]这个区间出现不合法的情况,我们输出 \(r-l+1\) 次 NO 并且他之后的小区间也不用遍历加边了,直接返回,否则直到叶子节点时输出 YES

当然返回要撤销对应的加边操作,我们用可撤销并查集,用栈储存当时的状态,不断回溯。

#include <bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1 
#define re register 
#define pb push_back
#define pir pair<int,int>
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define lb(x) x&(-x);
const int N=6e5+10;
const int mod=1e9+7;
using namespace std;

int n,m,k;
int u[N],v[N];
vector<int> t[N];
int fa[N],siz[N];
stack<pir> s;

int find(int x){
	while(x^fa[x]){
		x=fa[x];
	}
	return x;
}

void change(int p,int pl,int pr,int id,int l,int r){
	if(pl>=l&&pr<=r){
		t[p].push_back(id);
		return;
	}
	int mid=(pl+pr)>>1;
	if(l<=mid){
		change(ls,pl,mid,id,l,r);
	}
	if(r>mid){
		change(rs,mid+1,pr,id,l,r);
	}
}

void merge(int x,int y){
	if(x==y){
		return;
	}
	if(siz[x]>siz[y]){
		swap(x,y);
	}
	s.push({x,siz[x]==siz[y]});
	fa[x]=y;
	siz[y]+=(siz[x]==siz[y]); 
}

void solve(int p,int l,int r){
	int ok=1;
	int si=s.size();
	for(int i=0;i<t[p].size();i++){
		int id=t[p][i];
		int x=find(u[id]),y=find(v[id]);
		if(x==y){
			for(int j=l;j<=r;j++){
				cout<<"No\n";
			} 
			ok=0;
			break;
		}
		merge(find(u[id]+n),y);
		merge(find(v[id]+n),x);
	}
	if(ok){
		if(l==r){
			cout<<"Yes\n";
		}
		else{
			int mid=(l+r)>>1;
			solve(ls,l,mid);
			solve(rs,mid+1,r); 
		}
	}
	while(s.size()>si){
		int x=s.top().first;
		siz[fa[x]]-=s.top().second;
		fa[x]=x;
		s.pop();
	}
}

signed main(){
//	freopen("xp1.in","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(nullptr);
	cin>>n>>m>>k;
	
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>u[i]>>v[i]>>l>>r;
		if(l^r){
			change(1,1,k,i,l+1,r);
		}
	}	
	for(int i=1;i<=n;i++){
		fa[i]=i,siz[i]=1,fa[i+n]=i+n;
	}
	solve(1,1,k);
	return 0;
}

标签:P5787,int,题解,线段,fa,siz,区间,模板,define
From: https://www.cnblogs.com/sadlin/p/18593801

相关文章

  • 模板方法模式
    介绍定义:模板方法模式在一个方法中定义一个算法的骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义该算法的某些步骤。示例:/***咖啡因饮料冲泡法*/publicabstractclassCaffeineBeverage{/***模板方法,咖啡因饮料有......
  • 设计模式:21、模板方法模式
    目录0、定义1、模板方法模式的两种角色2、模板方法模式的UML类图3、示例代码0、定义       定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。1、模板方法模式的两种角色抽象模板......
  • P9951 [USACO20FEB] Swapity Swap B 题解
    题目传送门思路注意到\(1\leK\le10^9\),暴力显然会超时。将每次操作后的数列输出出来,发现会在一定次数的翻转后,重新回到初始数列。\(1\leN\le100\),循环节一定不会太长,所以暴力处理循环节长度即可。代码#include<bits/stdc++.h>usingnamespacestd;intn,lo,k,l1,l2,r......
  • 2024icpc上海E题题解及感想
    2024icpc上海E题题解​ 在这场icpc区域赛之前,我们队已经打了icpc南京和ccpc重庆,分别拿了银牌和铜牌。这场其实是非常希望可以拿金牌的,但是E题最后还是没能做出来,所以还是拿了一块银牌。​ 不过赛后拿到补题链接后用赛时思路写了一遍,发现赛时的思路假了。​ 但是后来转念一想,为......
  • [CF576E] Painting Edges 题解
    模版题的升级了。使用二分图经典判定方法(一个点拆成两个点\(x,x+n\),连边\((x,y)\)就是连接\((x,y+n),(x+n,y)\),那么是否是二分图就等价于判断\(x,x+n\)是否都不在一个集合内),预处理出每个操作的\(e_i\)下一次出现的位置\(nx_i\),每一次修改边相当于给\((i,nx_i)\)这个区......
  • 【Atcoder】【ABC383】A- Humidifier 1加湿器 题解
    前言不知道大家有没有关注过AtCoder这是小日子那边的一个网站,每周都会有比赛比起CF等等,最大的优点就是延迟低,题目质量也不错计划以后每周更新题解了正文题目传送门A-Humidifier1题目大意有一个加湿器,给定有次操作,第次在时间加入胜水然而,如果加湿器里有水,它每个单......
  • AT_arc188_a [ARC188A] ABC Symmetry 题解
    容易发现一个串是好的的充要条件是:A,B,C出现次数的奇偶性都相同。因此我们也可以将所有的串分为四类:好的,只有A和其他两个的奇偶性不同,只有B和其他两个的奇偶性不同,只有C和其他两个的奇偶性不同。大于\(k\)的不好统计,可以直接用总数减去小于\(k\)的总和。设$f_{i,x,......
  • 【题解】P8865 [NOIP2022] 种花
    题目传送门题目大意有一个\(n\timesm\)的花园,\(a_{i,j}=1\)表示可以种花,\(a_{i,j}=0\)表示不可以种花,请求出有多少种种花的的方案,使得形成C或F的形状,\(n,m\le10^3\)。思路分析观察C和F,发现F可以认为是C的左下角加一笔竖画,所以先求C。求形成C的方案数枚......
  • ABC383E 题解
    ABC383E题解题意给定一张包含\(n\)个节点和\(m\)条无向带权边的图,以及两个序列\(A_k,B_k\)分别表示图中的某些节点,定义\(f(A_i,B_j)\)为从\(A_i\)到\(B_j\)所有路径各自包含的边权最大值中的最小值,可以任意排列\(B\)中的元素,使得\(\sum_{i=1}^kf(A_i,B_i)\)最......
  • Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)-C
    题目大意一个\(H\)行和\(W\)列的网格图。\((i,j)\)表示从上到下第\(i\)行和从左到下第\(j\)列的单元格。每个单元格用字符\(S_{i,j}\)表示。如果\(S_{i,j}\)为#,则该单元格有一个障碍物;如果\(S_{i,j}\)是.则该单元格是空的;如果\(S_{i,j}\)为H,则该单元网格图......