2017 ACM/ICPC 新疆赛区 I 题 A Possible Tree 带权并查集

Posted draymonder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 ACM/ICPC 新疆赛区 I 题 A Possible Tree 带权并查集相关的知识,希望对你有一定的参考价值。

传送门 
题意:给定一棵带权树的形态, 但是并不知道每天条边的具体权重.

然后给m个信息, 信息格式为u v val, 表示在树上u 到 v 的路径上经过的边的权重的异或和为val, 问前面最多有多少个信息是不冲突的.

思路:首先很明显的我们要维护一系列不知道的信息, 看冲不冲突的那就是带权并查集没跑了, 此时r[v] 表示v到这棵树的根节点(虽然题目没给, 但是我们可以假设一个)的路径异或和, 那么此时的每条信息相当于是告诉你r[u] ^ r[v]的值, 注意异或的特性. 所以对于每条信息维护好当前的集合的信息, 如果遇到某次的连个点已经在一个集合中时, 那么他们之间的异或值也应该被确定了, 如果不等于题目的值那就是冲突的了… 压缩路径时根据r代表的意义, 所以就是r[v] ^= r[fav]; 这道题还是算带权并查集中较简单的那种…. 还是挺好的题目. 
去年比赛的时候还不会带权并查集(逃

注:注意bool型函数没有返回值会默认返回为false. 

 

 

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
int n, m , fa[N], V[N];
void init() {
    for(int i=0;i<=n;i++) {
        fa[i] = i;
        V[i] = 0;
    }
}

int Find(int x) {
    if(fa[x] == x) return x;
    int tmp = fa[x];
    fa[x] = Find(fa[x]);
    V[x] ^= V[tmp];
    return fa[x];
}

bool join(int u,int v,int k) {
    int fu = Find(u);
    int fv = Find(v);
    if(fu != fv) {
        fa[fu] = fa[fv];
        V[fu] = V[u]^V[v]^k;
        return true;
    }
    if((V[u]^V[v])!=k) return false;
    return true;
}

int main () {
    int T,cas; scanf("%d",&T);
    while (T--) {
        scanf("%d %d", &n, &m);
        init();
        for(int i=1; i<n; i++) {
            int u,v;
            scanf("%d %d",&u,&v);
        }
        int t = m+1;
        for(int i=1;i<=m;i++) {
            int u,v,val;
            scanf("%d %d %d",&u, &v, &val);
            if(t != m+1) continue;
            if(!join(u,v,val))
                t = i;
        }
        printf("%d
",t-1);
    }
    return 0;
}

 

以上是关于2017 ACM/ICPC 新疆赛区 I 题 A Possible Tree 带权并查集的主要内容,如果未能解决你的问题,请参考以下文章

2014ACM/ICPC亚洲区鞍山赛区现场赛——题目重现

2017 ACM/ICPC 北京赛区小结 By jsb @Reconquista

hdu 5956 The Elder 2016ACM/ICPC沈阳赛区现场赛I

2014ACM/ICPC亚洲区鞍山赛区现场赛题解报告

2017 ACM/ICPC 沈阳 I题 Little Boxes

2017 acm / icpc shenyang 双十一单身狗温馨重现赛