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.
AC Code

const int maxn = 1e5+5;
int fa[maxn], r[maxn];
int n;
void init() {
    for (int i = 0 ; i <= n ; i ++) {
        fa[i] = i;
        r[i] = 0;
    }
}
int Find(int x) {
    if (fa[x] == x) return x;
    else {
        int tmp = fa[x];
        fa[x] = Find(fa[x]);
        r[x] ^= r[tmp];
        return fa[x];
    }
}
bool Un(int u, int v, int s) {
    int fu = Find(u);
    int fv = Find(v);
    if (fu != fv) {
        fa[fu] = fv;
        r[fu] = r[u] ^ r[v] ^ s;
        return true;
    }
    if ((r[u] ^ r[v]) != s) return false;
    else return true;
}
void solve()
{
    int m;
    scanf("%d%d", &n, &m);
    init();
    for (int i = 1 ; i < n ; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
    }
    int flag = 0;
    for (int i = 1 ; i <= m ; i ++) {
        int u, v, s;
        scanf("%d%d%d", &u, &v, &s);
        if (!Un(u, v, s) && !flag) {
            flag = i;
        }
    }
    printf("%d\n", flag - 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值