zoukankan      html  css  js  c++  java
  • 牛客-小V和gcd树

    题目传送门

    sol:树剖解决,我们只维护每个节点和重儿子的边权,那么当一个节点权值改变时,也只需要修改该节点和其重儿子的边权,若该节点是其父亲节点的重儿子,则多修改一条该节点和其父亲节点的边权。查询操作时,若该节点不是父亲节点的重儿子,则暴力计算一次该节点和父亲节点的边权。

    • 树链剖分
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 20010;
      inline int read() {
          int n = 0, f = 1; char c = getchar();
          while (c < '0' || c > '9') {
              if (c == '-') f = -f;
              c = getchar();
          }
          while (c >= '0' && c <= '9') {
              n = 10 * n + (c ^ '0');
              c = getchar();
          }
          return f * n;
      }
      struct {
          int v, to;
      } edge[2 * MAXN];
      int head[MAXN];
      void add_edge(int u, int v) {
          static int tot = 0;
          edge[tot].v = v;
          edge[tot].to = head[u];
          head[u] = tot ++;
      }
      int fat[MAXN], son[MAXN], siz[MAXN], val[MAXN];
      void dfs1(int u, int f) {
          fat[u] = f, siz[u] = 1;
          for (int i = head[u]; i != -1; i = edge[i].to) {
              int v = edge[i].v;
              if (v == f) continue;
              dfs1(v, u);
              siz[u] += siz[v];
              if (siz[v] > siz[son[u]]) son[u] = v;
          }
      }
      int gcd[MAXN], dep[MAXN], top[MAXN], dfn[MAXN];
      void dfs2(int u, int t) {
          static int tot = 0;
          dfn[u] = ++ tot;
          dep[u] = dep[fat[u]] + 1;
          top[u] = t;
          if (t != u) gcd[dfn[u]] = __gcd(val[u], val[fat[u]]);
          if (son[u]) dfs2(son[u], t);
          for (int i = head[u]; i != -1; i = edge[i].to) {
              int v = edge[i].v;
              if (v == fat[u] || v == son[u]) continue;
              dfs2(v, v);
          }
      }
      int query(int u, int v, int k) {
          int ans = 0;
          while (top[u] != top[v]) {
              if (dep[top[u]] > dep[top[v]]) swap(u, v);
              for (int i = dfn[top[v]] + 1; i <= dfn[v]; i++)
                  ans += gcd[i] <= k;
              ans += __gcd(val[top[v]], val[fat[top[v]]]) <= k;
              v = fat[top[v]];
          }
          if (dep[u] > dep[v]) swap(u, v);
          for (int i = dfn[u] + 1; i <= dfn[v]; i++)
                  ans += gcd[i] <= k;
          return ans;
      }
      int main() {
          int n = read(), m = read();
          memset(head, -1, sizeof(head));
          for (int i = 1; i <= n; i++) val[i] = read();
          for (int i = 2; i <= n; i++) {
              int u = read(), v = read();
              add_edge(u, v), add_edge(v, u);
          }
          dfs1(1, 0), dfs2(1, 1);
          for (int i = 1; i <= m; i++) {
              if (read() == 1) {
                  int u = read(), k = read();
                  val[u] = k;
                  if (top[u] != u) {
                      gcd[dfn[u]] = __gcd(val[u], val[fat[u]]);
                  }
                  if (son[u]) {
                      gcd[dfn[son[u]]] = __gcd(val[u], val[son[u]]);
                  }
              } else {
                  int u = read(), v = read(), k = read();
                  printf("%d
      ", query(u, v, k));
              }
          }
          return 0;
      }

      ------------------------------------------------------------分隔线------------------------------------------------------------

      总结:$son,siz$必须在$dfs1$里求出;$dfn,top$必须在$dfs2$里求出;这次的错误是把$dfn$写到$dfs1$里面了,但是两次深搜的顺序是不一样的。第一次深搜就是按边的输入顺序进行搜索,第二次深搜在此基础上还优先搜索了重儿子。也正是因为优先搜索重儿子,才能保证重链的$dfs$序是连续的。

  • 相关阅读:
    cmd命令操作Mysql数据库
    可编程作息时间控制器设计
    博客第一天
    PRML 1: Gaussian Distribution
    KMP String Matching Algorithm
    Reinstall Ubuntu 14.04
    Computability 4: Decidability and R.E. Sets (I)
    Consumer-Producer Problem
    Compile the Linux Kernel
    Introduction to Linux Kernel
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/12908881.html
Copyright © 2011-2022 走看看