Beauty of Trees(带权并查集)

题目

https://www.nowcoder.com/acm/contest/119/A

题目大意

每次查询告诉你[l,r]之间的数的异或和,如果遇到不正确的查询,输出查询编号。

算法思路

  • 因为异或和前缀是不影响他的值,所以我们只需要将l和r连线,以异或值为权值,带权并查集即可。
  • 每次查询如果l和r在同一集合中,检查与其值是否相符即可。若不在,直接相连即可。
  • 带权并查集的操作
int Find(int x)
{
    if(x==fa[x])return x;
    int temp=fa[x];
    fa[x]=Find(fa[x]);//路径压缩
    rnk[x]=rnk[x]^rnk[temp];//更新rnk值
    return fa[x];
}

合并操作

 int ru=Find(u);
        int rv=Find(v);
        if(ru!=rv) {
            fa[ru]=rv;
            rnk[ru]=k^rnk[u]^rnk[v];
/*这里需要想一想;然后只更新了根节点的值,
子节点的值可以在后续查询find的时候更新*/
        }
  • 为了方便操作,采用左开右闭(常规操作)

代码

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1e5+5;
int fa[N];
ll rnk[N];
void Init(int n)
{
    for(int i=0;i<=n;i++)
    {
        fa[i]=i;
        rnk[i]=0;
    }
}
int Find(int x)
{
    if(x==fa[x])return x;
    int temp=fa[x];
    fa[x]=Find(fa[x]);
    rnk[x]=rnk[x]^rnk[temp];
    return fa[x];
}

int main()
{
    int n,m;
    while(cin>>n>>m){
        Init(n+1);
        int flag=0;
    for(int i=1;i<=m;i++){
         int u,v;
         ll k;
        scanf("%d%d%lld",&u,&v,&k);
        v++;
        int ru=Find(u);
        int rv=Find(v);
        if(ru!=rv) {
            fa[ru]=rv;
            rnk[ru]=k^rnk[u]^rnk[v];
        }
        else
        {
            if((rnk[v]^rnk[u])!=k) {flag=1;cout<<i<<endl;}
        }
    }
    if(!flag) cout<<-1<<endl;
    }
    return 0;
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 文章图片上传不正常,如需文档,可联系微信:1017429387 目录 1 安装... 4 1.1 配置探针... ...
    Mrhappy_a7eb阅读 6,653评论 0 5
  • 这个不错分享给大家,从扣上看到的,就转过来了 《电脑专业英语》 file [fail] n. 文件;v. 保存文...
    麦子先生R阅读 6,685评论 5 24
  • 点点和我,这是我们俩最好看最有feel的照片,于是闲下来之余把它画了下来。
    悟幻阅读 213评论 4 2
  • 2017年2月24日,阳光明媚,微风徐徐,上海二月的天依然带有一丝寒意。自从与Bob分手后,终日萎靡不振的,都没有...
    夕颜夕语阅读 481评论 6 5
  • 白月光 黄花地 树影斑驳 花阴沉沉 逐春 缓缓而行 有暗香盈袖
    叶一半阅读 139评论 0 1