• [Codeforces1055F] Tree and XOR


    (n) 个节点的树,有边权,路径长度为边权异或和。求 (n^2) 个点对之间路径长度的第 (k) 小(即 ((a, b),(b, a)) 算不同的两个,((a, a)) 的路径长度为 (0))。

    (n leq 10^6,val < 2^{62})

    (i) 到根的路径长度为 (d_i),那么任意两点 ((i, j)) 的路径长度都可表示为 (d_i oplus d_j)

    问题转化为求可重集合 ({D:D=d_i oplus d_j, 1 leq i, j leq n}) 的第 (k) 小。

    (d_i) 插入到 trie 里,从高位到低位考虑,如果 (D) 当前位为 (0) 的个数 (s geq k) 说明答案该为为 (0),否则为 (1)

    (D) 的当前位为 (0/1)(d_i oplus d_j = 0/1) 各有两种情况,乍一看每考虑一位状态数都会乘 2,但实际上每一层状态数最多都只有 (2n) 个。

    考虑到当前位时答案的高位已经确定了,设为 (ans),那么状态 (d_i) 只会和 (d_i oplus ans) 成对出现,所以最多有 (2n) 个状态。

    由于 (n leq 10^6),整个的 trie 存不下,所以像滚动数组一样,每次只存当前层的节点。

    #include <bits/stdc++.h>
    #ifdef LOCAL
    #define dbg(args...) std::cerr << "33[32;1m" << #args << " -> ", err(args)
    #else
    #define dbg(...)
    #endif
    inline void err() { std::cerr << "33[0m
    "; }
    template<class T, class... U>
    inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
    template <class T>
    inline void readInt(T &w) {
      char c, p = 0;
      while (!isdigit(c = getchar())) p = c == '-';
      for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
      if (p) w = -w;
    }
    template <class T, class... U>
    inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
    template <class T, class U>
    inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
    template <class T, class U>
    inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
    
    typedef long long LL;
    typedef std::pair<int, int> PII;
    
    constexpr int N(1e6 + 5);
    
    LL d[N];
    int id[N], ch[N][2], siz[N];
    
    int main() {
      int n; LL k;
      readInt(n, k);
      for (int i = 2, p; i <= n; i++) {
        readInt(p, d[i]), d[i] ^= d[p];
      }
      for (int i = 1; i <= n; i++) id[i] = 1;
      LL ans = 0;
      std::vector<PII> p = { PII(1, 1) }, np;
      for (int i = 61, c = 1, nc; ~i; i--, c = nc, p.swap(np)) {
        np.clear(), nc = 0;
        for (int j = 1; j <= c; j++) ch[j][0] = ch[j][1] = 0;
        for (int j = 1; j <= n; j++) {
          int k = d[j] >> i & 1;
          if (!ch[id[j]][k]) ch[id[j]][k] = ++nc, siz[nc] = 0;
          siz[id[j] = ch[id[j]][k]]++;
        }
        LL sum = 0;
        for (auto [x, y] : p) {
          sum += 1LL * siz[ch[x][0]] * siz[ch[y][0]] + 1LL * siz[ch[x][1]] * siz[ch[y][1]];
          if (sum >= k) break;
        }
        if (sum < k) {
          k -= sum, ans |= 1LL << i;
          for (auto [x, y] : p) {
            if (ch[x][0] && ch[y][1]) np.emplace_back(ch[x][0], ch[y][1]);
            if (ch[x][1] && ch[y][0]) np.emplace_back(ch[x][1], ch[y][0]);
          }
            
        } else {
          for (auto [x, y] : p) {
            if (ch[x][0] && ch[y][0]) np.emplace_back(ch[x][0], ch[y][0]);
            if (ch[x][1] && ch[y][1]) np.emplace_back(ch[x][1], ch[y][1]);
    
          }
        }
      }
      std::cout << ans;
      return 0;
    }
    
  • 相关阅读:
    谁把天才变成了魔兽
    NetBeans 时事通讯(刊号 # 35 Nov 20, 2008)
    Java Annotation 手册
    《程序设计实践》读书笔记一
    5分钟让你明白金融危机爆发原因
    NetBeans 6.5 正式版可以下载了!
    Java Annotation 入门
    有关睡觉的学问
    oracle sql日期比较:
    C++编写安全OCX,IE不弹出安全提示
  • 原文地址:https://www.cnblogs.com/HolyK/p/14162429.html
Copyright © 2020-2023  润新知