【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)
题目
分析:
从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下。
首先做这题之前推荐一道很相似的题:【BZOJ4025】二分图(可撤销并查集+线段树分治)
大力每个颜色维护一个并查集,就很像上面那道题了。但是存在一个问题:在处理线段树区间\([l,r]\)时,可能并不知道\(l\)处的修改是否成功,所以不知道\(l\)处修改的边具体是什么颜色的。
我的解决方案是:处理区间\([l,r]\)时忽略\(l\)处修改的边。先向左子树递归,递归到叶子时判断本次修改颜色能否成功。然后回溯后向右子树递归前将这条边加入。
代码:
solve函数的第四个参数表示现在是否已经忽略了\(l\)处修改的边。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <queue>
#include <bitset>
#include <stack>
using namespace std;
namespace zyt
{
	template<typename T>
	inline void read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != '-' && !isdigit(c));
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	inline void write(const char *const s)
	{
		printf("%s", s);
	}
	const int N = 5e5 + 10, B = 19, K = 51;
	int n, m, k, q, head[1 << (B + 1) | 11], ecnt;
	struct UFS
	{
		int fa[N], rk[N];
		bitset<N> dis;
		struct node
		{
			UFS &ufs;
			int x, y, fa, rk, dis;
		};
		static stack<node> sta;
		inline void init()
		{
			for (int i = 0; i < N; i++)
				fa[i] = i, rk[i] = 1;
			dis = 0U;
		}
		int f(const int x)
		{
			return x == fa[x] ? x : f(fa[x]);
		}
		int dist(const int x)
		{
			return x == fa[x] ? dis[x] : dist(fa[x]) ^ dis[x];
		}
		inline bool merge(const int u, const int v)
		{
			int x = f(u), y = f(v);
			if (x == y)
				return dist(u) ^ dist(v);
			if (rk[x] > rk[y])
				swap(x, y);
			sta.push((node){*this, x, y, fa[x], rk[y], dis[x]});
			fa[x] = y, dis[x] = dis[x] ^ dist(u) ^ dist(v) ^ 1;
			if (rk[x] == rk[y])
				++rk[y];
			return true;
		}
		static inline int set_undo()
		{
			return sta.size();
		}
		static inline void undo(const int bck)
		{
			while (sta.size() > bck)
			{
				UFS &now = sta.top().ufs;
				now.fa[sta.top().x] = sta.top().fa;
				now.rk[sta.top().y] = sta.top().rk;
				now.dis[sta.top().x] = sta.top().dis;
				sta.pop();
			}
		}
	}ufs[K];
	stack<UFS::node> UFS::sta;
	struct edge
	{
		int id, next;
	}e[N * B];
	inline void add(const int a, const int b)
	{
		e[ecnt] = (edge){b, head[a]}, head[a] = ecnt++;
	}
	struct ed
	{
		int u, v;
	}arr[N];
	struct node
	{
		int ed, col;
	}mdf[N];
	int pre[N], nxt[N], last[N];
	namespace Segment_Tree
	{
		void insert(const int rot, const int lt, const int rt, const int ls, const int rs, const int id)
		{
			if (ls <= lt && rt <= rs)
			{
				add(rot, id);
				return;
			}
			int mid = (lt + rt) >> 1;
			if (ls <= mid)
				insert(rot << 1, lt, mid, ls, rs, id);
			if (rs > mid)
				insert(rot << 1 | 1, mid + 1, rt, ls, rs, id);
		}
		void solve(const int rot, const int lt, const int rt, bool flag)
		{
			int mid = (lt + rt) >> 1;
			int bck = UFS::set_undo();
			bool f = false;
			for (int i = head[rot]; ~i; i = e[i].next)
			{
				int now = e[i].id;
				if (lt == now)
				{
					flag = true;
					continue;
				}
				UFS &u = ufs[mdf[now].col];
				ed &edg = arr[mdf[now].ed];
				if (mdf[now].col)
					u.merge(edg.u, edg.v);
			}
			if (lt == rt)
			{
				if (!ufs[mdf[lt].col].merge(arr[mdf[lt].ed].u, arr[mdf[lt].ed].v))
					mdf[lt].col = mdf[pre[lt]].col, write("NO");
				else
					write("YES");
				putchar('\n');
			}
			else
			{
				solve(rot << 1, lt, mid, f | flag);
				if (f | flag)
					ufs[mdf[lt].col].merge(arr[mdf[lt].ed].u, arr[mdf[lt].ed].v);
				solve(rot << 1 | 1, mid + 1, rt, false);
			}
			UFS::undo(bck);
		}
	}
	int work()
	{
		using namespace Segment_Tree;
		memset(head, -1, sizeof(head));
		read(n), read(m), read(k), read(q);
		for (int i = 1; i <= k; i++)
			ufs[i].init();
		for (int i = 1; i <= m; i++)
			read(arr[i].u), read(arr[i].v);
		for (int i = 1; i <= q; i++)
		{
			read(mdf[i].ed), read(mdf[i].col);
			nxt[i] = q + 1;
		}
		for (int i = 1; i <= q; i++)
		{
			if (last[mdf[i].ed])
				pre[i] = last[mdf[i].ed];
			last[mdf[i].ed] = i;
		}
		for (int i = q; i > 0; i--)
			nxt[pre[i]] = i;
		for (int i = 1; i <= q; i++)
			insert(1, 1, q, i, nxt[i] - 1, i);
		solve(1, 1, q, false);
		return 0;
	}
}
int main()
{
	return zyt::work();
}
【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)的更多相关文章
- 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic
		本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ... 
- 【BZOJ4025】二分图(可撤销并查集+线段树分治)
		题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ... 
- [CSP-S模拟测试]:地理课(并查集+线段树分治)
		题目传送门(内部题146) 输入格式 从$geography.in$读入数据. 第一行两个数$n,m$,表示有$n$个点,$m$个时刻.接下来$m$行每行三个数,要么是$1\ u\ v$,要么是$2\ ... 
- UVA1455 - Kingdom(并查集 + 线段树)
		UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum ... 
- 并查集&线段树&树状数组&排序二叉树
		超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ... 
- BZOJ 3910 并查集+线段树合并
		思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ... 
- bzoj 3237 连通图 - 并查集 - 线段树
		Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connected Disconne ... 
- 【xsy2506】 bipartite 并查集+线段树
		题目大意:有$n$个点,你需要操作$m$次.每次操作为加入/删除一条边. 问你每次操作后,这$n$个点构成的图是否是二分图. 数据范围:$n,m≤10^5$. 此题并没有强制在线,考虑离线做法. 一条 ... 
- 并查集 + 线段树 LA 4730 Kingdom
		题目传送门 题意:训练指南P248 分析:第一个操作可以用并查集实现,保存某集合的最小高度和最大高度以及城市个数.运用线段树成端更新来统计一个区间高度的个数,此时高度需要离散化.这题两种数据结构一起使 ... 
随机推荐
- 67.基于nested object实现博客与评论嵌套关系
			1.做一个实验,引出来为什么需要nested object 冗余数据方式的来建模,其实用的就是object类型,我们这里又要引入一种新的object类型,nested object类型 博客,评论,做 ... 
- Centos下Yum安装PHP5.5,5.6,7.0及扩展
			默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们 ... 
- journals in Fluid Dynamics
			annual review of fluid mechanicsjournal of fluid mechanicsphysics of fluidjournal of flow and struct ... 
- Spring核心技术(二)——Spring的依赖及其注入
			本文将继续前文,描述Spring IoC中的依赖处理. 依赖 一般情况下企业应用不会只有一个对象(或者是Spring Bean).甚至最简单的应用都要多个对象来协同工作来让终端用户看到一个完整的应用的 ... 
- Introduction to TensorFlow
			Lecture note 1: Introduction to TensorFlow Why TensorFlow TensorFlow was originally created by resea ... 
- HDU1507 Uncle Tom's Inherited Land*
			题目是跟 zoj1516是一样的,但多了匹配后的输出 详解zoj1516可见http://www.cnblogs.com/CSU3901130321/p/4228057.html #include & ... 
- sdibt  1244类似于拓扑排序
			博客:http://blog.csdn.net/mypsq/article/details/39005991 #include<stdio.h> #include<string.h& ... 
- The Evaluation of Determinant(求行列式mod一个数的值)
			#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #i ... 
- 洛谷——P1255 数楼梯
			题目描述 楼梯有N阶,上楼可以一步上一阶,也可以一步上二阶. 编一个程序,计算共有多少种不同的走法. 输入输出格式 输入格式: 一个数字,楼梯数. 输出格式: 走的方式几种. 输入输出样例 输入样例# ... 
- MySQL基于域名做高可用切换(Consul初试)
			一,Consul功能介绍 服务发现 - Consul的客户端可用提供一个服务,比如 api 或者mysql ,另外一些客户端可用使用Consul去发现一个指定服务的提供者.通过DNS或者HTTP应用程 ... 
