Codeforces 888G Xor-MST - 分治 - 贪心 - Trie

题目传送门

  这是一条通往vjudge的高速公路

  这是一条通往Codeforces的高速公路

题目大意

  给定一个$n$阶完全图,每个点有一个权值$a_{i}$,边$(i, j)$的权值是$(a_{i}\  xor\  a_{j})$。一个生成树的权值是各边的权值和。问最小生成树的权值。  

  设值域为$[0, 2^{k})$。

  当$k = 1$的时候,显然将点权为0的点之间互相连边,点权为1的点之间互相连边,中间随便连一条。

  当$k = x\ (x > 1)$的时候,将这些点按照二进制的第$k$位分成两个集合。因为这两集合中间的点互相连边,边权的第$k$位会被消掉,于是变成了$k = x - 1$的子问题。

  假如得到了它们的最优解,那么我只需要在两个连通块之间添加一条边权最小的边就行了。

  考虑怎么找这样一条边。

  我可以把其中一个集合中数插入Trie树,然后拿另一集合中的点的点权在Trie树中查最小异或和。

Code

  1 /**
  2  * Codeforces
  3  * Problem#888G
  4  * Accepted
  5  * Time: 327ms
  6  * Memory: 49772k
  7  */
  8 #include <bits/stdc++.h>
  9 #ifndef WIN32
 10 #define Auto "%lld"
 11 #else
 12 #define Auto "%I64d"
 13 #endif
 14 using namespace std;
 15 typedef bool boolean;
 16
 17 #define ll long long
 18
 19 typedef class TrieNode {
 20     public:
 21         TrieNode* ch[2];
 22
 23         TrieNode():ch({NULL, NULL}) {    }
 24 }TireNode;
 25
 26 TrieNode pool[6000000];
 27 TrieNode* top = pool;
 28
 29 TrieNode* newnode() {
 30     top->ch[0] = top->ch[1] = NULL;
 31     return top++;
 32 }
 33
 34 typedef class Trie {
 35     public:
 36         TrieNode* rt;
 37
 38         Trie() {
 39             top = pool;
 40             rt = newnode();
 41         }
 42
 43         void insert(int x, int dep) {
 44             int temp = 1 << dep, d;
 45             TrieNode *p = rt;
 46             while (temp) {
 47                 d = (temp & x) ? (1) : (0);
 48                 if (!p->ch[d])
 49                     p->ch[d] = newnode();
 50                 p = p->ch[d], temp = temp >> 1;
 51             }
 52         }
 53
 54         int query(int x, int dep) {
 55             int temp = 1 << dep, rt = 0, d;
 56             TrieNode *p = this->rt;
 57             while (temp) {
 58                 d = (temp & x) ? (1) : (0);
 59                 if (p->ch[d])
 60                     p = p->ch[d];
 61                 else
 62                     p = p->ch[d ^ 1], rt |= temp;
 63                 temp = temp >> 1;
 64             }
 65             return rt;
 66         }
 67 }Trie;
 68
 69 int n;
 70 int *ar;
 71 Trie t;
 72
 73 inline void init() {
 74     scanf("%d", &n);
 75     ar = new int[(n + 1)];
 76     for (int i = 1; i <= n; i++)
 77         scanf("%d", ar + i);
 78 }
 79
 80 ll dividing(int dep, int l, int r) {
 81     if (!dep)    return ar[l] ^ ar[r];
 82     int tl = l, tr = r, mid, temp = 1 << dep, mincost = 1 << 30;
 83     while (tl <= tr) {
 84         mid = (tl + tr) >> 1;
 85         if (ar[mid] & temp)
 86             tr = mid - 1;
 87         else
 88             tl = mid + 1;
 89     }
 90     if (tr == l - 1 || tr == r)
 91         return dividing(dep - 1, l, r);
 92     t = Trie();
 93     for (int i = l; i <= tr; i++)
 94         t.insert(ar[i], dep);
 95     for (int i = tr + 1; i <= r; i++)
 96         mincost = min(mincost, t.query(ar[i], dep));
 97     return mincost + dividing(dep - 1, l, tr) + dividing(dep - 1, tr + 1, r);
 98 }
 99
100 inline void solve() {
101     sort(ar + 1, ar + n + 1);
102     printf(Auto"\n", dividing(29, 1, n));
103 }
104
105 int main() {
106     init();
107     solve();
108     return 0;
109 }

原文地址:https://www.cnblogs.com/yyf0309/p/8505004.html

时间: 2024-08-04 02:51:04

Codeforces 888G Xor-MST - 分治 - 贪心 - Trie的相关文章

Codeforces 1111C Creative Snap分治+贪心

Creative Snap C. Creative Snap time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Thanos wants to destroy the avengers base, but he needs to destroy the avengers along with their base. Let we

codeforces 455B A Lot of Games (Trie + dfs)

题目大意: 两个人往一个空的字符串里填单词,每一次只能填一个,而且填完之后要是给出的N个字符串的前缀. 思路分析: 先用给出的所有单词建字典树. 然后从根节点开始dfs. win [x] 表示踩在x节点上是否有必胜策略 lose [x] 表示踩在x节点上是否有必败策略. 然后是博弈的过程. 如果先手有必胜和必败的策略,那么他可以一直输到k-1 如果只有必胜策略.那么只有当k为奇数的时候它才能赢. 其他为后手赢. #include <cstdio> #include <iostream&g

Codeforces 442B Andrey and Problem(贪心)

题目链接:Codeforces 442B Andrey and Problem 题目大意:Andrey有一个问题,想要朋友们为自己出一道题,现在他有n个朋友,每个朋友想出题目的概率为pi,但是他可以同时向多个人寻求帮助,不过他只能要一道题,也就是如果他向两个人寻求帮助,如果两个人都成功出题,也是不可以的. 解题思路:贪心,从概率最大的人开始考虑,如果询问他使得概率变大,则要询问. #include <cstdio> #include <cstring> #include <a

Codeforces Round #300-Tourist&#39;s Notes(贪心)

Tourist's Notes Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Description A tourist hiked along the mountain range. The hike lasted for n days, during each day the tourist noted height above the sea level

Codeforces 432E Square Tiling(构造+贪心)

我们通常这么写 using (SqlDataReader drm = sqlComm.ExecuteReader()) { drm.Read();//以下把数据库中读出的Image流在图片框中显示出来. MemoryStream ms = new MemoryStream((byte[])drm["Logo"]); Image img = Image.FromStream(ms); this.pictureBox1.Image = img; } 我的写数据 private void b

[51nod 1295]Xor key(可持久化trie)

[51nod 1295]Xor key(可持久化trie) 题面 给出一个长度为n的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R).求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少? 分析 可持久化trie裸题 代码 #include<iostream> #include<cstdio> #define maxb 31 #define maxn 200000 #define maxs 6

Codeforces.888G.Xor-MST(Bor?vka算法求MST 贪心 Trie)

题目链接 \(Description\) 有一张\(n\)个点的完全图,每个点的权值为\(a_i\),两个点之间的边权为\(a_i\ xor\ a_j\).求该图的最小生成树. \(n\leq2*10^5,0\leq ai<2^{30}\). \(Solution\) 代码好神啊. 依旧是从高到低考虑每一位.对于当前位i,如果所有点在这一位都为0或1,不需要管(任何边在这一位都为0). 否则可以把点分为两个集合,即i位为0和1的集合,这两个集合间必须存在一条边,且边权这一位只能为1. 考虑怎么高

Codeforces Round #177 (Div. 1) C. Polo the Penguin and XOR operation(贪心)

题目地址:http://codeforces.com/problemset/problem/288/C 思路:保证位数尽量大的情况下使得每二进制位均为一的情况下结果最大,从后向前枚举(保证位数尽量大),num表示该数i二进制有几位,x即为使得与i异或后每二进制位均为一的数,v[x]标记是否使用过该数,若未使用则与i搭配. #include<cstdio> #include<cmath> #include<cstring> #include<iostream>

Codeforces Round #256 (Div. 2) C. Painting Fence(分治贪心)

题目链接:http://codeforces.com/problemset/problem/448/C ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593830943