POJ 1733 Parity game (带权并查集)

题意:有序列A[1..N],其元素值为0或1。有M条信息,每条信息表示区间[L,R]中1的个数为偶数或奇数个,但是可能有错误的信息。求最多满足前多少条信息。

分析:区间统计的带权并查集,只是本题中路径的运算是用模2或异或逻辑。而且需要注意的是,本题N可达1e9,但M只有5000,所以最多出现的坐标只有1e4,离散化处理。

区间[L,R]1的奇偶可转化为将L-1视作R的父亲节点,其距离就是1的奇偶。注意如果M条信息都正确,那么结果是M。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int maxn =1e4+5;
const int INF= 0x3f3f3f3f;
int fa[maxn];
int dist[maxn];
void init(int N)
{
    for(int i=0;i<=N;++i) fa[i]=i,dist[i]=0;
}

int Find(int x)
{
    if(fa[x]==x) return x;
    int f = fa[x];
    fa[x] = Find(fa[x]);
    dist[x] =(dist[x]+dist[f])%2;
    return fa[x];
}

bool Union(int a,int b,int op)
{
    int roota= Find(a),rootb = Find(b);
    if(roota==rootb && (dist[a]+op)%2!=dist[b]) return false;
    fa[rootb] = roota;
    dist[rootb] =(op+dist[a]-dist[b]+2)%2; 
    return true;
}

map<int,int> dp;

int main()
{
    #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
    #endif
    int T,N,M,Q,u,v,tmp,K;
    int a,b;
    char op[6];
    while(scanf("%d%d",&N,&M)==2){
        dp.clear();
        init(10000);
        int cnt=1,ans=0;
        for(int i=1;i<=M;++i){
            scanf("%d%d%s",&a,&b,op);
            if(!dp[a-1]) dp[a-1]= cnt++;
            if(!dp[b]) dp[b] = cnt++;
            if(op[0]=='e'){
                if(!Union(dp[a-1],dp[b],0) && !ans) ans=i;
            }
            else{
                if(!Union(dp[a-1],dp[b],1) && !ans) ans=i;
            }
        }
        if(!ans) ans=M+1;
        printf("%d
",ans-1);
    }
    return 0;
}
为了更好的明天
原文地址:https://www.cnblogs.com/xiuwenli/p/9412770.html