Parity game(poj-1733)(带权并查集+离散化)

题目

前置芝士
带权并查集
离散化

思路
先求一遍前缀和 设每次询问为 l,r,ans 由前缀和的性质我们知道 ,
如果 sum[l~r]=‘odd’ 说明 sum[r]和sum[l-1] 的奇偶性不同,一奇一偶,否则说明两者奇偶性相同,同为奇数或者同为偶数。
这题我们考虑带权并查集
设边权d[x]为0,表示x和fa[x]的奇偶性相同,如果d[x]为1,表示x和fa[x]的奇偶性不同 在进行路径压缩时,对x到树根的所有边权做异或运算,可以得到x和树根的关系
对每个询问,设ans表示该问题的回答(0代表偶 1代表奇)

先检查x和y是否在同一个集合内,(奇偶关系是否已知) 如果在同一个集合内 并且d[x]^d[y]!=ans 则该关系和回答矛盾,可以确定撒慌
否则合并x和y的两个集合,设两个集合的树根分别为x1和y1,令fa[x1]=y1, 已知d[x],d[y]分别表示路径x与x1, y 与y1 的奇偶性,x~y之间的奇偶性为ans,显然ans=d[x]^ d[y] ^d[x1],所以,d[x1]=ans ^ d[x] ^d[y]

最后,因为n的范围为1e9,数组开不了这么大的范围,所以我们需要对l-1和r,这两个点进行离散化

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> PII;
int d[maxn];
int fa[maxn];
int a[maxn];
int t;
struct query
{
    int l,r,ans;
}qr[maxn];



int find(int x)
{
    if(x==fa[x])
        return x;
    int f=fa[x];
    fa[x]=find(fa[x]);
    d[x]^=d[f];
    return fa[x];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        char ch[5];
        cin>>qr[i].l>>qr[i].r>>ch;
        qr[i].ans=(ch[0]=='o'?1:0);
        a[++t]=qr[i].l-1;
        a[++t]=qr[i].r;
    }
    sort(a+1,a+1+t);
    n=unique(a+1,a+1+t)-a-1;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x=lower_bound(a+1,a+1+n,qr[i].l-1)-a;
        int y=lower_bound(a+1,a+1+n,qr[i].r)-a;
        int x1=find(x),y1=find(y);
        if(x1==y1)
        {
            if((d[x]^d[y])!=qr[i].ans)
                {
                    cout<<i-1<<endl;
                    return 0;
                }
        }
        else
        {
            fa[x1]=y1;
            d[x1]=qr[i].ans^d[x]^d[y];
        }
    }
    cout<<m<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值