Beauty of Trees

题意:n个数,m个信息:L,R,k。每个信息表示a[L]^a[L+1]^a[L+2]^····^a[R]=k。如果第 i 个信息与前面 i-1 个信息矛盾的话就输出 i ,如果这m个信息都不矛盾的话,输出 -1

题解:位运算多半要考虑二进制,这里将k分解成二进制形式。先令dp[i][j]表示第i个数之前(包括第i个数),二进制第j位为1的数的个数。如果k的二进制的第j位为1的话,说明区间[L,R]中这一位为1的数有奇数个(区间的数考虑成二进制),那么dp[L-1][j]和dp[R][j]的奇偶性相同,为啥呢?因为奇数减奇数等于偶数,偶数减偶数等于偶数~~~~~。同理可以分析出如果k的二进制的第j位为0的话,说明区间[L,R]中这一位为1的数有偶数个,那么dp[L-1][R]和dp[R][j]的奇偶性不同。小技巧出现啦^_^,对每一位开一个虚拟节点,用并查集管理,如果dp[L-1][j]和dp[R][j]的奇偶性不同,那么实点和虚点相连。奇偶性相同,就实点和实点相连,虚点和虚点相连。显然判断是否矛盾的方式也就自然出来了:奇偶性相同,但在并查集中确是实点和虚点连在了一起,说明矛盾。-----------------参考华中校赛题解

#pragma warning(disable:4996)
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mem(arr,in) memset(arr,in,sizeof(arr))
using namespace std;

const int maxn = 200010;

int n, m;
int pa[maxn][32];

int Find(int a, int j) {
    if (pa[a][j] == a) return a;
    return pa[a][j] = Find(pa[a][j], j);
}

void Union(int a, int b, int j) {
    int x = Find(a, j);
    int y = Find(b, j);
    if (x != y) pa[x][j] = y;
    return;
}

void Inite() {
    for (int i = 0; i <= 2 * n + 1; i++) {
        for (int j = 0; j <= 30; j++) {
            pa[i][j] = i;
        }
    }
    return;
}

int main()
{
    while (cin >> n >> m) {
        Inite();
        int cnt = 0;
        for (int i = 1; i <= m; i++) {
            int l, r, k;
            cin >> l >> r >> k;
            l--;

            bool flag = false;
            for (int j = 0; j <= 30; j++) {
                int tp = k & (1 << j);
                if(tp==0){
                    if (Find(l, j) == Find(r + n + 1, j) || Find(r, j) == Find(l + n + 1, j)){
                       printf("%d\n", i);
                        flag = true;
                        break; 
                    }
                }
                else{
                    if(Find(l, j) == Find(r, j) || Find(l + n + 1, j) == Find(r + n + 1, j)){
                        printf("%d\n", i);
                        flag = true;
                        break;
                    }
                }
                
            }
            if (flag) continue;

            cnt++;
            for (int j = 0; j <= 30; j++) {
                int tp = k & (1 << j);
                if (tp == 0) {
                    Union(l, r, j);
                    Union(l + n + 1, r + n + 1, j);
                }
                else {
                    Union(l, r + n + 1, j);
                    Union(l + n + 1, r, j);
                }
            }
        }
        if (cnt == m) cout << "-1" << endl;
    }
    return 0;
}

 

posted @ 2018-05-15 21:34  天之道,利而不害  阅读(260)  评论(0编辑  收藏  举报