zoukankan      html  css  js  c++  java
  • HDU 6191 Query on A Tree

    可持久字典树。

    询问子树可以转化为询问一段区间,因此可以对树的$dfs$序进行操作。因为是在一群数字中找一个数字和已知数字异或最大,所以可以想到字典树。保存前缀字典树,然后询问区间$[L,R]$的时候,只要$R$的字典树减去$L-1$的字典树就是区间$[L,R]$上的的数字构成的字典树。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 100000 + 10;
    int n, a[maxn];
    int sz, h[maxn], to[maxn], nx[maxn];
    int L[maxn], R[maxn];
    int num, b[2 * maxn];
    int q;
    struct Node {
      int son[2];
      int cnt;
    }s[65 * maxn];
    int root[2 * maxn];
    
    void addedge(int u, int v) {
      to[sz] = v;
      nx[sz] = h[u];
      h[u] = sz;
      sz ++;
    }
    
    void dfs(int x) {
      b[++ num] = a[x];
      L[x] = num;
      for(int i = h[x]; i != -1; i = nx[i]) {
        dfs(to[i]);
      }
      b[++ num] = a[x];
      R[x] = num;
    }
    
    int addnode() {
      num ++;
      s[num].son[0] = -1;
      s[num].son[1] = -1;
      s[num].cnt = 0;
      return num;
    }
    
    int work(int x, int y) {
      int res = 0;
      int p1 = root[L[x] - 1];
      int p2 = root[R[x]];
      for(int i = 30; i >= 0; i --) {
        int u = (1 << i) & y;
        u = u ? 1 : 0;
        if(p1 == -1) {
          if(s[p2].son[u ^ 1] != -1) {
            res = res + (1 << i);
            p2 = s[p2].son[u ^ 1];
          } else {
            p2 = s[p2].son[u];
          }
        } else {
          if(s[p2].son[u ^ 1] == -1) {
            p1 = s[p1].son[u];
            p2 = s[p2].son[u];
          } else {
            if(s[p1].son[u ^ 1] == -1) {
              res = res + (1 << i);
              p1 = s[p1].son[u ^ 1];
              p2 = s[p2].son[u ^ 1];
            } else {
              if(s[s[p1].son[u ^ 1]].cnt < s[s[p2].son[u ^ 1]].cnt) {
                res = res + (1 << i);
                p1 = s[p1].son[u ^ 1];
                p2 = s[p2].son[u ^ 1];
              } else {
                p1 = s[p1].son[u];
                p2 = s[p2].son[u];
              }
            }
          }
        }
      }
      return res;
    }
    
    int main() {
    
      while(~scanf("%d%d", &n, &q)) {
        num = sz = 0;
        for(int i = 1; i <= n; i ++) {
          h[i] = -1;
        }
        for(int i = 1; i <= n; i ++) {
          scanf("%d", &a[i]);
        }
        for(int i = 1; i <= n - 1; i ++) {
          int x;
          scanf("%d", &x);
          addedge(x, i + 1);
        }
        dfs(1);
    
        num = 0;
        root[0] = 0;
        s[0].son[0] = -1;
        s[0].son[1] = -1;
        s[0].cnt = 0;
    
        for(int i = 1; i <= 2 * n; i ++) {
          root[i] = addnode();
          int p1 = root[i - 1];
          int p2 = root[i];
          s[p2].son[0] = s[p1].son[0];
          s[p2].son[1] = s[p1].son[1];
          s[p2].cnt = s[p1].cnt;
          for(int j = 30; j >= 0; j --) {
            int x = (1 << j) & b[i];
            x = x ? 1 : 0;
            if(p1 == -1) {
              int id = addnode();
              s[id].cnt ++;
              s[p2].son[x] = id;
              p2 = id;
            } else {
              p1 = s[p1].son[x];
              int id = addnode();
              if(p1 != -1) {
                s[id].son[0] = s[p1].son[0];
                s[id].son[1] = s[p1].son[1];
              }
              if(p1 != -1) {
                s[id].cnt = s[p1].cnt + 1;
              } else {
                s[id].cnt = 1;
              }
              s[p2].son[x] = id;
              p2 = id;
            }
          }
        }
    
        for(int i = 1; i <= q; i ++) {
          int x, y;
          scanf("%d%d", &x, &y);
          int ans = work(x, y);
          printf("%d
    ", ans);
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    csu 1604 SunnyPig (bfs)
    openjudge 大师兄,师傅被妖怪抓走啦
    poj 3264 线段树 求区间最大最小值
    bzoj 1012 维护一个单调数列
    poj 1840 暴力+标记
    最短路径(Dijkstra实现)
    最小生成树(Kruskal实现)
    最小生成树(Prim实现)
    拓扑排序(Kahn实现)
    拓扑排序(DFS实现)
  • 原文地址:https://www.cnblogs.com/zufezzt/p/7492847.html
Copyright © 2011-2022 走看看