Poj P1733 Parity game___带权并查集+hash

30 篇文章 0 订阅
14 篇文章 0 订阅

题目大意:

MLi,Ri,strstreven[Li,Ri]11N 给 出 M 个 区 间 的 描 述 L i , R i , s t r , 当 s t r 为 e v e n 时 , 表 示 区 间 [ L i , R i ] 有 偶 数 个 1 , 否 则 有 奇 数 个 1 , 题 目 会 给 出 区 间 的 最 大 长 度 N 。

N109 N ≤ 10 9
M104 M ≤ 10 4

分析:

首 先 我 们 可 以 想 到 ,
①奇-偶=奇
②奇-奇=偶
③偶-偶=偶
所以,当
区间 [L,R]1 [ L , R ] 内 的 1 ,即 Sum[l,r] S u m [ l , r ] 有偶数个,
那么显然 Sum[l,r]=Sum[1,r]Sum[1,l1] 因 为 S u m [ l , r ] = S u m [ 1 , r ] − S u m [ 1 , l − 1 ]
所以 Sum[1,r]Sum[1,l1] S u m [ 1 , r ] 和 S u m [ 1 , l − 1 ] 的奇偶性相同
同理 Sum[l,r] S u m [ l , r ] 有奇数个,
那么 Sum[1,r]Sum[1,l1] S u m [ 1 , r ] 和 S u m [ 1 , l − 1 ] 的奇偶性不同
那么我们可以考虑用带权并查集去做,
d[x]=0xfather d [ x ] = 0 时 表 示 x 与 其 f a t h e r 奇 偶 性 相 同
d[x]=1xfather d [ x ] = 1 时 则 表 示 x 与 其 f a t h e r 奇 偶 性 不 同
那么可以通过 xor x o r 运算求出 x x 与当前集合的树根z奇偶性
对于一个区间 [l,r]Sum[l,r] [ l , r ] 以 及 他 们 的 S u m [ l , r ]
我们显然可以发现,当
l1r l − 1 与 r 不 在 同 一 个 集 合 中 的 时 候 , 就 可 以 连 边
l1xry 设 点 l − 1 的 集 合 的 树 根 为 x , r 的 集 合 的 树 根 为 y ,
然后 xy x 向 y 连边即可
可是这时候的 d[x] d [ x ] 该 怎 么 求 呢 ?
我 们 已 经 知 道
l1rSum[l,r] l − 1 到 r 的 奇 偶 性 S u m [ l , r ]
l1xdl1 l − 1 到 x 的 奇 偶 性 d l − 1
rydr r 到 y 的 奇 偶 性 d r
那么显然可以得到
dx=Sum[l,r] d x = S u m [ l , r ] xor dl1 d l − 1 xor dr d r
l1,r l − 1 , r 在 同 一 个 集 合 的 时 候 ,就判断
dl1 d l − 1 xor dr d r 的奇偶性判断是否有解即可
Ml,rl,rmaphash 因 为 M 很 小 而 l , r 很 大 , 所 以 我 们 可 以 对 l , r 进 行 m a p 或 者 h a s h

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define modn 20011
#define N 100005

using namespace std;

map <int, int> Map;

struct Node {
    int l, r, w;
}a[N];
int Hash[modn][2], f[N], d[N], n, m, cnt;

int Getid(int x) {
    int k = x % modn;
    while (Hash[k][0] && Hash[k][0] != x) {
        k++;
        if (k = modn) k = 0;
    }
    if (!Hash[k][0]) Hash[k][1] = ++cnt;
    Hash[k][0] = x;
    return k;
}

int Find(int x) {   
    if (f[x] == x) return x;
    int rp = Find(f[x]);
    d[x] = d[x] ^ d[f[x]];
    return f[x] = rp;
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < modn; i++) f[i] = i, d[i] = 0;
    for (int i = 1; i <= m; i++) {
         char str[5];
         scanf("%d %d %s", &a[i].l, &a[i].r, str);
         a[i].l--;
         if (str[0] == 'e') a[i].w = 0;
                       else a[i].w = 1;
         Getid(a[i].l);
         Getid(a[i].r);
    }
    for (int i = 1; i <= m; i++) {
         int idx = Getid(a[i].l);
         int idy = Getid(a[i].r);
         int p = Find(idx);
         int q = Find(idy);
         if (p == q) {
             if (d[idx] ^ d[idy] != a[i].w) {
                 printf("%d\n", i - 1);
                 return 0;
             }
         } else f[p] = q, d[p] = d[idx] ^ d[idy] ^ a[i].w;
    }
    printf("%d\n", m);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值