zoukankan      html  css  js  c++  java
  • 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
    ", i);
                            flag = true;
                            break; 
                        }
                    }
                    else{
                        if(Find(l, j) == Find(r, j) || Find(l + n + 1, j) == Find(r + n + 1, j)){
                            printf("%d
    ", 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;
    }
  • 相关阅读:
    安装VMtools vim编辑器的使用 压缩包命令 Linux下的用户管理 (第三天)
    VM虚拟机安装 常用Linux命令 网卡配置 (第二天)
    数据库的交互模式 常用的dos命令 (第一天)
    Validate US Telephone Numbers FreeCodeCamp
    Arguments Optional FreeCodeCamp
    Everything Be True FreeCodeCamp
    Binary Agents FreeCodeCamp
    Steamroller FreeCodeCamp
    Drop it FreeCodeCamp
    Smallest Common Multiple FreeCodeCamp
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9043158.html
Copyright © 2011-2022 走看看