parity game(一道并查集的毒瘤题)

Posted 。✧* ꧁王者꧂✧*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了parity game(一道并查集的毒瘤题)相关的知识,希望对你有一定的参考价值。

题面如下:
           \\;\\;\\;\\;\\; 有一个01序列,长度n<=1000000000,现在有t条信息,每条信息的形式是:a ,b even/odd,表示第a位到第b位元素之间的元素总和是偶数/奇数。 你的任务是对于这些给定的信息,输出第一个不正确的信息所在位置-1。信息的数目不超过5000。 如果信息全部正确,那么输出t。

           \\;\\;\\;\\;\\; 看到这道题的第一眼:???这竟然是并查集??怎么有点交互题的味道~~
           \\;\\;\\;\\;\\; 虽然这道题对于大佬们来说so easy,但我这样的蒟蒻道行还是不够。
开始正文:
           \\;\\;\\;\\;\\; 对于这道题,我们并不一定要求出原序列到底是什么样子的(当然,我们也求不出来),但是,我们可不可以从另一个角度来考虑一下。既然不能求出具体的值,那我是不是只要维护奇偶性就可以了呢?
           \\;\\;\\;\\;\\; 答案是显然的。就比如,输入:34,45,even,这就相当于sum[45]-sum[33]的值为偶数(sum数组指前缀和,这里只是为了帮助理解而使用的,代码中用不上),也就是意味着,sum[45]和sum[33]的奇偶性相同。那么,我们就可以对33和45进行并查集的维护了。
           \\;\\;\\;\\;\\; 同理,若输入为: L,R,odd\\even,若输入为odd,则代表sum[L-1]与sum[R]奇偶性不同,若为even则相反。
           \\;\\;\\;\\;\\; 原理知道了,那接下来我们就来说一下该如何维护奇偶性吧。
           \\;\\;\\;\\;\\; 若是你思考过就会发现,很多时候,题目可能会给你好几段连续的区间,这些连续的区间肯定是要合并的,这样才能继续维护接下来的状态,也就是说,我们需要用并查集维护每一段给出的区间(包括没给出的,但是已经合并过的)的奇偶性。
           \\;\\;\\;\\;\\; 这就要用到加权并查集了(就是在“找爸爸”和合并时同时维护其他的状态)。
           \\;\\;\\;\\;\\; 对于奇偶性的判断,我们可以类似于树的深度加和那样(并查集本质也就是一颗树),但是,这道题中用的不是加和,而是异或。我们可以对每一颗树(每一组并查集)维护从当前节点到根节点的边权的异或和(相连的两个节点,奇偶性相同,边权为0,奇偶性不同,边权为1)。然后,若d[i]^d[j]=1(i和j这俩节点在同一组并查集中才能进行异或操作),则说明i与j的奇偶性不同,若值为0,则奇偶性相同。
           \\;\\;\\;\\;\\; 那么,我们就可以通过这个来判断当前题目中给出的信息是对还是错了。
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n,a,b,ans,fa[N],root,c[N],cnt,d[N];
char s[10];
struct ao
{
	int l,r;
	bool ans;
	#define l(x) e[x].l
	#define r(x) e[x].r
	#define ans(x) e[x].ans
}e[N];
int get(int x)
{
	if(x==fa[x]) return x;
	int root=get(fa[x]);
	d[x]^=d[fa[x]];//边权赋值 
	return fa[x]=root;//路径压缩 
}
int main()
{
	scanf("%d%d",&n,&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%d%d%s",&e[i].l,&e[i].r,s+1);
		c[++cnt]=e[i].l,c[++cnt]=e[i].r;
		if(s[1]=='o') e[i].ans=1;
	}
	sort(c+1,c+cnt+1);
	int len=unique(c+1,c+cnt+1)-(c+1);
	for(int i=1;i<=len;i++) fa[i]=i;
	for(int i=1;i<=t;i++)
	{
		l(i)=lower_bound(c+1,c+len+1,l(i)-1)-c;//以r(i)为终点的前缀和 与 以l(i)-1为终点的前缀和 会有奇偶性相同 或 奇偶性不同的关系 
		r(i)=lower_bound(c+1,c+len+1,r(i))-c;
		int fx=get(l(i));
		int fy=get(r(i));
		if(fx==fy)
		{
			if((d[l(i)]^d[r(i)])!=ans(i))
			{
				cout<<i-1;
				return 0;
			} 
		} 
		else
		{
			fa[fx]=fy,d[fx]=d[l(i)]^d[r(i)]^ans(i);//连接两颗树 
		}
	}
	cout<<t;
	return 0;
}

以上是关于parity game(一道并查集的毒瘤题)的主要内容,如果未能解决你的问题,请参考以下文章

poj1733 Parity Game(扩展域并查集)

poj 1733 Parity game - 并查集

Parity game POJ - 1733 带权并查集

poj 1733 Parity game(带权并查集)

Parity game——带权并查集

poj 1733 Parity game(种类并查集)