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;
View Code

 

 

 

 

 

以上是关于Parity game——带权并查集的主要内容,如果未能解决你的问题,请参考以下文章

Parity game——带权并查集

「带权并查集」奇偶游戏

总结一下我理解的带权并查集

并查集——poj2236(带权并查集)

CF553C Love Triangles(带权并查集)

HDU 3047 Zjnu Stadium 带权并查集