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(一道并查集的毒瘤题)的主要内容,如果未能解决你的问题,请参考以下文章