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

题意:题意:给你一个n,表示有一串长为n的由0和1组成的串,之后给你m次操作 a b op ,其中op表示是even 表示a到b的和是偶数,o表示的是奇数,现在问你在第几次操作的时候你发现他和之前矛盾。

思路:这算是做的第一道利用到了离散化的题目了。这题的带权并查集的路径压缩操作和权值的计算和前两天写的[题目]https://blog.csdn.net/yiqzq/article/details/80152561特别像,强烈建议第一次写带权并查集的同学先去学习一下。如果你会了上面这题,接下来要做的只是离散化区间,(说明一下为什需要离散化,因为你会发现题目中给出的区间长度特别大,范围有1e9,显然你如果开数组的话是开不了这么大的,这时候你又会发现题目中给出的查询次数只有5000,这样的话,假设区间不重复,也最多只用到了10000个点,那么多余的空间不就浪费掉了嘛)。回到离散化,如果还没有学习的同学,可以去这篇博客去学习一下。

那么这题是需要我们离散化区间的,而不是值,那该怎么样呢?
解:很简单啦,我们只需要将区间的两个端点值都进行离散化就ok了。

还有一点,如何去计算权值,我们可以每次将结果相加再%2就行了。

举个例子:
我们知道区间[1,3]是奇数,我们记为1,区间[4,8]是偶数,我们记为0,那么区间[1,8]的奇偶性就是(0+1)%2=1.
下面上代码:

#include 
#include 
#include 
#include 
using namespace std;
const int add = 4;
const int maxn = 50005;
int n, m,num[maxn] ,f[maxn], val[maxn];
struct node {
    int a, b, c;
} e[maxn];
int getf(int v) {
    if(f[v] == v) return v;
    int t = f[v];
    f[v] = getf(f[v]);
    val[v] = (val[v] + add + val[t]) % 2;//压缩路径时要进行权值更新
    return f[v];
}
void init() {
    for(int i = 0; i < maxn; i++) {
        val[i] = 0;
        f[i] = i;
        num[i] = 0;
    }
}
int main() {
init();
    int flag = 1;
    int cnt = 0;
    scanf("%d%d", &n, &m);
    char op[10];
    for(int i = 0; i < m; i++) {
        scanf("%d%d%s", &e[i].a, &e[i].b, op);
        e[i].a--;//减1是为方便区间计算,细节可以去上面所说的博客去看
        if(op[0] == 'e') e[i].c = 0;
        else e[i].c = 1;
        num[cnt++] = e[i].a;
        num[cnt++] = e[i].b;
    }
    /*
    离散化一般操作步骤
    1.拷贝数据样本
    2.使用sort排序
    3.使用unique函数去重
    4.使用lower_bound()映射
    */
    sort(num, num + cnt);
    int k = unique(num, num + cnt) - num;
    for(int i = 0; i < m; i++) {
        int nx = lower_bound(num, num + k, e[i].a) - num;
        int ny = lower_bound(num, num + k, e[i].b) - num;
        int x = getf(nx);
        int y = getf(ny);
        if(x != y) {
            f[y] = x;
            val[y] = (val[nx] + e[i].c - val[ny] + add) % 2;//每次加一个add是为了防止出现负数
        } else if(x == y && e[i].c != (val[ny] - val[nx] + add) % 2) {
            printf("%d\n", i);
            flag = 0;
            break;
        }
    }
    if(flag) printf("%d\n", m);
    return 0;
}

你可能感兴趣的:(ACM_并查集)