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

    题目传送门

    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\n", query(u, v, k));
              }
          }
          return 0;
      }

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

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

  • 相关阅读:
    1104 Sum of Number Segments (20 分)(数学问题)
    1092 To Buy or Not to Buy (20 分)(hash散列)
    1082 Read Number in Chinese (25 分)(字符串处理)【背】
    1105 Spiral Matrix (25 分)(模拟)
    初识网络安全及搭建网站(内网)
    HTML5开发者需要了解的技巧和工具汇总(转)
    native+web开发模式之web前端经验分享
    移动平台3G手机网站前端开发布局技巧汇总(转)
    Asp.net 中图片存储数据库以及页面读取显示通用方法详解附源码下载
    使用H3Viewer来查看VS2010的帮助文档
  • 原文地址:https://www.cnblogs.com/Jathon-cnblogs/p/12908881.html
Copyright © 2011-2022 走看看