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;
}

原文地址:https://www.cnblogs.com/j666/p/11615302.html

时间: 2024-08-30 12:53:09

Parity game——带权并查集的相关文章

POJ 1773 Parity game 带权并查集

分析:带权并查集,就是维护一堆关系 然后就是带权并查集的三步 1:首先确定权值数组,sum[i]代表父节点到子节点之间的1的个数(当然路径压缩后代表到根节点的个数) 1代表是奇数个,0代表偶数个 2:设计路径压缩算法 sum[x]=(sum[x]+sum[t])%2; 3:弄清合并根节点时的操作,小的在上: 注:这个题需要离散化 #include <stdio.h> #include <string.h> #include <algorithm> using names

POJ - 1733 Parity game 带权并查集+离散化

题目大意:有10E位数,每位上的数不是1就是0.现在给出第n位到第m位的1的数量的奇偶性,判断所给出的话有几句是对的 解题思路:有10E位数,肯定要离散化处理 因为有可能给出的区间是左端点等于右端点的,所以每次都把左端点的值减去1再进行处理 给出了区间的奇偶性,就要找一下是否和前面的矛盾,如果该区间的左端点的根节点和右端点的根节点是相同的,那么就可以判断是否正确了 如果根节点不同,就进行合并,合并时要注意判断是谁的根节点比较大 #include<cstdio> #include<algo

并查集练习2(带权并查集)

明天旅游去爬山逛庙玩,今天练一天然后早早睡觉啦~ poj1703 Find them, Catch them (带权并查集) 1 #include<cstdio> 2 const int N=1e5+1; 3 int f[N]; 4 int r[N];//表示与父节点的关系,0同类,1不同类 5 int n; 6 void init(){ 7 for(int i=1;i<=n;++i){ 8 f[i]=i; r[i]=0; 9 } 10 } 11 int fin(int x){ 12 i

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

总结一下我理解的带权并查集 与普通并查集的区别:普通的并查集仅仅记录的是集合的关系,这个关系无非是同属一个集合或者是不在一个集合,而带权并查集是记录集合内元素的关系,而这个关系被带上了一个权值表示集合内元素之间关系的区别,例如食物链这道题,权值为0表示和根节点是同类,权值为1表示吃根节点... 用向量法来表示带权并查集 查询是否在同一个集合,或者同一个集合内的元素如何表示他们之间的关系 ??? 每个元素带一个权值用rank表示 如上图,用向量法表示则是a->root+a->b=b->ro

hdu3038(带权并查集)

题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=3038 题意: n表示有一个长度为n的数组, 接下来有m行形如x, y, d的输入, 表示从第x,个元素到第y个元素的和为d(包括x, 和y), 问m行输入里面有几个是错误的(第一个输入是正确的); 思路: 很显然带权并查集咯,我们可以用距离的概念代替和的概念比较好理解一点,d表示x到y的和即x到y的距离; 可以用rank[x]表示x到其父亲节点的距离,  将正确的距离关系合并到并查集中

【POJ1182】 食物链 (带权并查集)

Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类. 第二种说法是"2 X Y",表示X吃Y. 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的.当一句话满足下列三条之

【poj 1988】Cube Stacking(图论--带权并查集 模版题)

题意:有N个方块,M个操作{“C x”:查询方块x上的方块数:“M x y”:移动方块x所在的整个方块堆到方块y所在的整个方块堆之上}.输出相应的答案. 解法:带权并查集.每堆方块作为一个集合,维护3个数组:fa[x]表示x方块所在堆的最顶部的方块:d[x]表示x方块所在堆的最底部的方块:f[x]表示x方块方块x上的方块数. 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<

Lightoj1009 Back to Underworld(带权并查集)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Back to Underworld Time Limit:4000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Description The Vampires and Lykans are fighting each other to death. The war has become so fierc

[NOIP摸你赛]Hzwer的陨石(带权并查集)

题目描述: 经过不懈的努力,Hzwer召唤了很多陨石.已知Hzwer的地图上共有n个区域,且一开始的时候第i个陨石掉在了第i个区域.有电力喷射背包的ndsf很自豪,他认为搬陨石很容易,所以他将一些区域的陨石全搬到了另外一些区域. 在ndsf愉快的搬运过程中,Hzwer想知道一些陨石的信息.对于Hzwer询问的每个陨石i,你必须告诉他,在当前这个时候,i号陨石在所在区域x.x区域共有的陨石数y.以及i号陨石被搬运的次数z. 输入描述: 输入的第一行是一个正整数T.表示有多少组输入数据. 接下来共有