poj 1733 Parity game

Parity game

题意:一个长度为N(N < 1e9)内的01串,之后有K(K <= 5000)组叙述,表示区间[l,r]之间1的个数为odd还是even;问在第一个叙述矛盾前说了几句话?

Sample Input

10 N
5 K
1 2 even
3 4 odd
5 6 even
1 6 even  (错误)
7 10 odd

Sample Output

3

思路:对于判断正误的问题,一定要知道什么情况会导致错误。如样例:当前输入的区间[1,6]的端点均包含于前面输入的端点中时(包含并不是指区间相同而是区间延拓(使用并查集))后可以计算出来该区间的奇偶即可,那么易知并查集中合并的元素就为区间的端点,对端点标记(离散化)之后和hdu3047一样处理下压缩时当前节点到根节点路径中1的奇偶即可;

**区间延拓:原本区间的表示可以[l,r],但是会发现不能将相邻的区间如[1,2]和[3,4]合并(因为区间没有相同的端点),那么就(l,r]这样就变成了(0,2]&(2,4];可以实现延拓(实现细节)

ps:对于mod2的加减运算,就是XOR,但是全部将mod2替换成XOR竟然用时更长;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
map<int,int> mp;
const int MAXN = 5050*2;
int f[MAXN];
int kind[MAXN];
int Find(int a)
{
     if(a == f[a]) return f[a];
     int fa = Find(f[a]);
     kind[a] ^= kind[f[a]];//这是当前的fa并没有压缩,但是f[fa]已经压缩了,dist[]里面还是要写f[a],而不是fa
     return f[a] = fa;
}
bool _union(int u,int v,int d)//union时将区间的奇偶标记在子节点上;
{
    int fu = Find(u),fv = Find(v);
    if(fu == fv){
        if((kind[u] ^ kind[v]) != d) return true;//区间端点XOR得到区间的奇偶;不是[fu] ^[fv]的xor
        return false;
    }
    f[fu] = fv;
    kind[fu] = kind[v]^d^kind[u]; //偏移向量 等同于kind[fu] = (kind[v]+d-kind[u]+2)%2;
    return false;
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    int x,y,id = 0,ret;
    char s[5];
    bool flag = false;
    rep1(i,0,MAXN) f[i] = i,kind[i] = 0;
    rep0(i,0,k){
        scanf("%d%d%s",&x,&y,s);//(x-1,y];区间延拓;
        if(flag) continue;
        int d = (s[0] == ‘e‘)?0:1;
        if(mp.find(--x) == mp.end()){
            mp[x] = ++id;
        }
        if(mp.find(y) == mp.end()){
            mp[y] = ++id;
        }
        if(_union(mp[x],mp[y],d)){
            ret = i;flag = true;
        }
    }
    printf("%d\n",flag?ret:k);
    return 0;
}

时间: 2024-10-15 02:43:44

poj 1733 Parity game的相关文章

[2016-03-18][POJ][1733][Parity game]

时间:2016-03-18 09:55:52 星期五 题目编号:[2016-03-18][POJ][1733][Parity game] 题目大意:给定若干的区间范围内的数字的和,问从哪句开始是错误的 分析: 带权并查集 区间长度高达1000000000显然不可能直接建立数组,但是发现询问只有5000次,也就是最多出现了5000*2个点,离散化就可以解决问题 relation[i] i为区间的左端点,fa[i]为区间的右端点,relation[i]维护(i,fa[i])这段区间的和的奇偶状态,0

poj 1733 Parity game 并查集 离散化

点击打开链接题目链接 Parity game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6249   Accepted: 2413 Description Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You cho

poj 1733 Parity game【哈希+并查集】

这道题题意我不想说了,但是有一个条件必须的说,就是1-2其实是0-2这条边,3-4是2-4这条边,但是困惑了好久,其他就是哈希给他一个地址 ,然后把注解看下方 #include <stdio.h> #include <string.h> #define maxx 10001 int par[maxx]; int rank[maxx]; void init() { for(int i=0;i<=maxx;i++) { rank[i]=0; par[i]=i; } } int f

poj 1733 Parity game(带权并查集)

题目链接:http://poj.org/problem?id=1733 题意:给出一个01串然后给出一系列问题,问最多到哪位置问题出错了 这题和hdu3038类似思路也是差不多的 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> using namespace std; struct TnT { int l

POJ 1733 Parity game (并查集)

Parity game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6816   Accepted: 2636 Description Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You choose a conti

poj 1733 Parity game 【种类并查集+离散化】

Parity game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6767   Accepted: 2616 Description Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You choose a conti

Poj 1733 Parity Game(离散化+并查集)

 题目大意:给出n个数字,m个区间内的数字和的奇偶性,询问从哪句话开始出现错误. 1.对于给定区间[l , r]的奇偶性,可以转化为[1. l-1]和[1, r]的奇偶性"关系",这样就可以用带权并查集来做了,权值为当前结点与根节点的奇偶性关系,每次查询如果l,r根结点相同,那么判断这句话是否正确,如果根节点不同,那么合并. 2.由于这道题数据量很大,但是查询只有m(m<=5000)所以要先将数据离散化.对于离散化,有两种方法,一种是考虑元素大小相对关系的,一种是不需要考虑元

poj 1733 Parity game(种类并查集)

题意: 有0或1构成的一段区间总长度为n.m个询问,每次询问一段区间1的个数为奇数还是偶数,问从第一个询问開始,前几个询问正确的个数有几个: 思路: n<=10^9,m<=5000;非常多数用不到,所以能够离散化一下: 将和为奇数的区间标记为1,为偶数的区间标记为0. 对于每一个询问,合并操作时.假设两区间重合且奇偶性之和与询问所给的奇偶性同样,则该询问正确,否则错误: 若区间不重合.合并区间,并合并奇偶性: #include<cstdio> #include<cstring

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

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