Parity game——带权并查集
Posted j666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Parity game——带权并查集相关的知识,希望对你有一定的参考价值。
题意:
你一个字符串,由0和1组成,并且告诉你子串里面1的个数,假设前面的话都是对的,问你到哪一句和前面的话矛盾。
题解:
首先,发现n很大,但是问题数m不多,所以先离散化
d数组表示序列S的前缀和
d[l~r]有偶数个1,等价于d[l-1]与d[r]奇偶性相同。
d[l~r]有奇数个1,等价于d[l-1]与d[r]奇偶性不同。
然后通过异或满足上面传递关系 即 奇偶性相同异或为偶 奇偶性不同异或为奇
集合合并方法与 How Many Answers Are Wrong 类似
d【i】 表示 1到i的和 如果存在 【i,a】与【i,b】 则只要判断 【b,i】^【a-1,i】的奇偶性即可
所以用并查集维护公共点 即根节点 (其实d【i】可以看作根节点到 i 的距离)
那么集合如何合并?
先让fx指向fy 即 f[fy]=fx; 因为 d[fx]^d[x]^d[y]=a[i].ans 所以 d[fx]^d[x]^d[y]=a[i].ans
代码:
#include<iostream> #include<stdio.h> #include<math.h> #include<algorithm> #include<vector> using namespace std; typedef long long ll; const int maxn = 2e5+7; vector<int>v; int f[maxn],d[maxn]; int get_id(int x)return lower_bound(v.begin(),v.end(),x)-v.begin()+1; struct node int l,r,ans; a[maxn]; int Find(int x) if(f[x]==x)return x; int root=Find(f[x]); d[x]^=d[f[x]]; return f[x]=root; int main() int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) char str[10]; scanf("%d%d%s",&a[i].l,&a[i].r,str); v.push_back(a[i].l-1); v.push_back(a[i].r); a[i].ans=(str[0]==‘e‘?0:1); sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end()); for(int i=1; i<=v.size(); i++)f[i]=i,d[i]=0; int res=m; for(int i=1; i<=m; i++) int x=get_id(a[i].l-1); int y=get_id(a[i].r); int fx=Find(x); int fy=Find(y); if(fx==fy) if((d[x]^d[y])!=a[i].ans) res=i-1; break; else f[fx]=fy; d[fx]^=d[x]^d[y]^a[i].ans; /// d[fx]^d[x]^d[y]=a[i].ans printf("%d\\n",res); return 0;
以上是关于Parity game——带权并查集的主要内容,如果未能解决你的问题,请参考以下文章