• 牛客-XOR TREE


    题目传送门

    sol:假如把这题树上这个条件改成序列,那么对于操作2,求某区间$[l, r]$所有连续子序列的异或和。观察得出若$r - l + 1$是偶数,则答案是$[l, r]$区间的异或和。否则,答案是$[l, r]$区间内下标奇偶性与$l$不同的元素的异或和。那么可以用三颗线段树来分别维护奇数下标、偶数下标、所有下标的异或和。至于在树上完成操作,树剖解决。

    • 树剖 + 线段树
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 2e5 + 10;
      inline int read() {
          int n = 0; char c = getchar();
          while (c < '0' || c > '9') c = getchar();
          while (c >= '0' && c <= '9') {
              n = 10 * n + (c ^ '0');
              c = getchar();
          }
          return n;
      }
        
      struct {int v, n;} edge[2 * MAXN];
      int val[MAXN], head[MAXN];
      void add_edge(int u, int v) {
          static int cnt = 1;
          edge[cnt].v = v;
          edge[cnt].n = head[u];
          head[u] = cnt++;
      }
      // 树剖
      int fat[MAXN], son[MAXN], siz[MAXN], dep[MAXN];
      int top[MAXN], rnk[MAXN], ord[MAXN];
      void dfs(int u, int f, int d) {
          fat[u] = f, dep[u] = d, siz[u] = 1;
          for (int i = head[u]; i != -1; i = edge[i].n) {
              int v = edge[i].v;
              if (v == fat[u]) continue;
              dfs(v, u, d + 1);
              siz[u] += siz[v];
              if (siz[v] > siz[son[u]]) {
                  son[u] = v;
              }
          }
      }
      void dfs(int u, int t) {
          static int cnt = 1;
          top[u] = t, ord[u] = cnt, rnk[cnt++] = u;
          if (!son[u]) return;
          dfs(son[u], t);
          for (int i = head[u]; i != -1; i = edge[i].n) {
              int v = edge[i].v;
              if (v == fat[u] || v == son[u]) continue;
              dfs(v, v);
          }
      }
        
      // 线段树
      struct SegTree {
          struct Node {
              int l, r;
              int val;
          } node[4 * MAXN];
          void build(int i, int l, int r) {
              node[i].l = l, node[i].r = r;
              node[i].val = 0;
              if (l == r) return;
              int mid = l + r >> 1;
              build(i << 1, l, mid);
              build(i << 1 | 1, mid + 1, r);
          }
          void update(int i, int ind, int val) {
              if (node[i].l == node[i].r) {
                  node[i].val = val;
                  return;
              }
              int mid = node[i].l + node[i].r >> 1;
              if (ind <= mid) update(i << 1, ind, val);
              else update(i << 1 | 1, ind, val);
              node[i].val = node[i << 1].val ^ node[i << 1 | 1].val;
          }
          int query(int i, int l, int r) {
              if (node[i].l == l && node[i].r == r) return node[i].val;
              int mid = node[i].l + node[i].r >> 1;
              if (r <= mid) return query(i << 1, l, r);
              if (l > mid) return query(i << 1 | 1, l, r);
              return query(i << 1, l, mid) ^ query(i << 1 | 1, mid + 1, r);
          }
      } tree[3];
      // 求路径和
      int query(int u, int v) {
          int val = 0, tag;
          int tu = top[u], tv = top[v];
          if ((dep[u] & 1) != (dep[v] & 1)) tag = 2;
          else tag = !(dep[u] & 1);
          while (tu != tv) {
              if (dep[tu] >= dep[tv]) { // 跳tu到u
                  val ^= tree[tag].query(1, ord[tu], ord[u]);
                  u = fat[tu], tu = top[u];
              } else {
                  val ^= tree[tag].query(1, ord[tv], ord[v]);
                  v = fat[tv], tv = top[v];
              }
          }
          if (dep[u] <= dep[v]) {
              val ^= tree[tag].query(1, ord[u], ord[v]);
          } else {
              val ^= tree[tag].query(1, ord[v], ord[u]);
          }
          return val;
      }
      // 主函数
      int main() {
          int n = read(), m = read();
          for (int i = 1; i <= n; i++) val[i] = read();
          memset(head, -1, sizeof(head));
          for (int i = 2; i <= n; i++) {
              int u = read(), v = read();
              add_edge(u, v);
              add_edge(v, u);
          }
          dfs(1, -1, 1);
          dfs(1, 1);
          tree[0].build(1, 1, n), tree[1].build(1, 1, n), tree[2].build(1, 1, n);
          for (int i = 1; i <= n; i++) {
              tree[dep[i] & 1].update(1, ord[i], val[i]);
              tree[2].update(1, ord[i], val[i]);
          }
          for (int i = 1; i <= m; i++) {
              int op = read();
              if (op == 1) {
                  int ind = read(), val = read();
                  tree[dep[ind] & 1].update(1, ord[ind], val);
                  tree[2].update(1, ord[ind], val);
              } else {
                  int u = read(), v = read();
                  printf("%d
      ", query(u, v));
              }
          }
          return 0;
      }

      因为这道题专门去学了树剖,这题的数据真的是很玄学啊。我一样的代码第一次提交过80%数据超时,之后提交就能AC。另外一份感觉复杂度一样的代码一直过80%数据超时。最后20%数据有毒。

  • 相关阅读:
    Rancher 中 Traefik 负载均衡 Initializing 状态
    【音视频】YUV、RGB视频像素处理
    Debian WSL 2 安装使用 Docker
    CentOS 7 切换 Java 版本到 Java 11
    阿里云 CentOS 8.2 停服后 yum / dnf 无法安装更新
    CentOS 8 Stream 报错处理 Faild to start Load Kernel Modules. Failed to insert 'ipmi_si': No such device
    System.getProperty()获取系统变量
    简单科普私钥、地址、助记词、Keystore的区别
    synchronized实现原理及锁升级过程
    H3C 策略路由原理介绍
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/12420785.html
Copyright © 2020-2023  润新知