2020牛客暑期多校训练营(第五场)B、D、E、F、I题解及补题

文章目录2020牛客暑期多校训练营(第五场)题解及补题比赛过程题解A题意解法代码B题意解法代码C题意解法代码D题意解法代码E题意解法代码F题意解法代码G题意解法代码H题意解法代码I题意解法代码J题意解法代码K题意解法代码2020牛客暑期多校训练营(第五场)题解及补题比赛过程这场打出了排名新低,总结原因是前期还行中规中矩,后期两个中等难度的签到题罚时炸了。D和E犯了很多低级的错误,其中E不够熟悉大数板子,而且一开始过于急躁随便就觉得是把所有长度乘起来wa了之后才去认真思考,以后可以多花时间验证思想正确性
摘要由CSDN通过智能技术生成

2020牛客暑期多校训练营(第五场)题解及补题

比赛过程

这场打出了排名新低,总结原因是前期还行中规中矩,后期两个中等难度的签到题罚时炸了。D和E犯了很多低级的错误,其中E不够熟悉大数板子,而且一开始过于急躁随便就觉得是把所有长度乘起来wa了之后才去认真思考,以后可以多花时间验证思想正确性,纯感觉流不太行。E思路正确,代码挫了,码力有待提升。

题解

A

题意
解法
代码
//将内容替换成代码

B

题意

n n n个点的一棵树,可以任意增减边(要求图联通且环的异或和为0),问修改后的树最小权值和。

解法

首先可以注意到,无论如何增删边,不会改变两个点路径的边的异或和,那么我们可以由这个特性给每个点一个权值,答案即为异或最小生成树。计算异或最小生成树主要用到了是 B o r u v k a Boruvka Boruvka算法和01字典树,因为其中有一个求最小异或对的过程,暴力是 n 2 n^2 n2的复杂度, t r i e trie trie可以用来优化第二层循环,因为对于每个数我们可以从高到低的去贪心选择数位一样的数。 B o r u v k a Boruvka Boruvka算法重点在于思想本身,这个算法一般情况下比 p r i m prim prim k r u s k a l kruskal kruskal要麻烦得多不会用但是在边权由两个点点权决定的题里有奇效, b o r u v k a boruvka boruvka相当于是两个思想的结合,多源的去做 p r i m prim prim

代码
#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 111;
const ll mod = 1e9 + 7;
#define P pair<int, int>
int trie[maxn * 32][2], idx;
vector<P> G[maxn];
int val[maxn];
void add(int a) {
   
    int p = 0;
    for (int i = 29; i >= 0; --i) {
   
        bool tp = a & (1 << i);
        if (!trie[p][tp]) trie[p][tp] = ++idx;
        p = trie[p][tp];
    }
}
int query(int a) {
     //查找和a异或最小的数
    int p = 0, ans = 0;
    for (int i = 29; i >= 0; --i) {
   
        bool tp = a & (1 << i);
        if (trie[p][tp]) {
   
            p = trie[p][tp];
        } else {
   
            ans |= (1 << i);
            p = trie[p][!tp];
        }
    }
    return ans;
}
void dfs(int u, int fa) {
   
    for (auto v : G[u]) {
   
        if (v.first == fa) continue;
        val[v.first] = val[u] ^ v.second;
        dfs(v.first, u);
    }
}
ll ans;
void solve(int id, int l, int r) {
   
    if (id < 0) return;
    int mid = l - 1;
    while (mid < r && (val[mid + 1] & (1 << id)) == 0) mid++;
    if (l <= mid) solve(id - 1, l, mid);
    if (mid + 1 <= r) solve(id - 1, mid + 1, r);
    if (l <= mid && mid + 1 <= r) {
   
        for (int i = l; i <= mid; i++) add(val[i]);
        int minn = INT_MAX;
        for (int i = mid + 1; i <= r; i++) minn = min(minn, query(val[i]));

        for (int i = 0; i <= idx; ++i) {
   
            trie[i][0] = trie[i][1] = 0;
        }
        idx = 0;
        ans += minn;
    }
}
int main() {
   
    int n;
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) {
   
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值