第十四届华中科技大学程序设计竞赛决赛同步赛 A Beauty of Trees 区间并查集(异或类似加减法)

并查集解决树校验问题
本文介绍了一个使用并查集及路径压缩技术解决树校验问题的方法。该问题涉及一系列树木的高度及其异或和的校验。通过构建并查集并利用路径压缩优化查询过程,可以有效地找出不符合逻辑的消息。
It’s universally acknowledged that there’re innumerable trees in the campus of HUST.
One day the tree manager wants to play a game with you. There are N trees lining up in a straight road. The beauty of a set of trees is defined as the bitwise XOR sum of the heights of these trees. The game will last for M rounds, and each time he will tell you an interval [L i,R i] and its beauty. However, he mixed some fake messages with the correct ones. Your task is to find the messages that cannot logically correspond to its former correct messages. Otherwise you’ll think the message is correct.

输入描述:

The first line contains two integer N and M(1≤N,M≤105), the number of trees and the rounds of game.
Then M lines followed, in each line are three integer L, R and k(1≤L≤R≤N,0≤k≤109), indicating that the beauty of [Li,Ri] is k.

输出描述:

If the i-th message is wrong, then print i in a single line.
If there is no mistake, print -1.

题意:有n个数,每次给你一个信息l, r, k,代表a[l] ^ a[l+1] ^ ... ^ a[r] = k,问你哪些信息是错误的,如果x信息和y信息可以x对y错或者x错y对,那么认为先给出的信息是对的。

思路:(学长提供)

并查集路径压缩。 记a数组的前缀异或和是sum,那么信息l, r, k实际上就是sum[r] ^ sum[l-1] = k,如果已知sum[r] ^ sum[x] = k1, sum[l-1] ^ sum[x] = k2,那么只要判断k1 ^ k2是否等于k即可,否则设sum[r] ^ sum[x] = k1, sum[l-1] ^ sum[y] = k2,那么有sum[x] ^ sum[y] = k1 ^ k2 ^ k,可以将合并x,y,并设sum[x]^sum[y] = k1^k2^k, 然后直接用路径压缩就好了。

与HDU 3088类似 https://blog.youkuaiyun.com/deepseazbw/article/details/79324733

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int parent[N];
int sum[N];  //记录当前结点到根结点的距离
int root(int x)
{
    if(parent[x]==x) return x;//一直到寻找到根节点
    int t=parent[x];           //存贮中间节点
    parent[x]=root(parent[x]);
    sum[x]^=sum[t];
    return parent[x];
}
void merge(int x,int y,int a,int b,int v)
{
    parent[x]=y;
    sum[x]=sum[b]^sum[a]^v;
 
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        vector<int> vec;
        for(int i=0; i<=n; i++)
            parent[i]=i;
        memset(sum,0,sizeof(sum));
        int a,b,v;
        for(int pos=1; pos<=m; pos++)
        {
            scanf("%d%d%d",&a,&b,&v);
            a--;
            int x=root(a);
            int y=root(b);
            if(x==y)   //同根节点,但值不为之前的事实
            {
                if((sum[a]^sum[b])!=v)
                    vec.push_back(pos);
            }
            else
            {
                merge(x,y,a,b,v);
            }
        }
        if(!vec.size())
            vec.push_back(-1);
        for(int i=0; i<vec.size(); i++)
            printf("%d\n",vec[i]);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值