zoukankan      html  css  js  c++  java
  • [luoguP3178] [HAOI2015]树上操作(dfs序 + 线段树 || 树链剖分)

    传送门

    树链剖分固然可以搞。

    但还有另一种做法,可以看出,增加一个节点的权值会对以它为根的整棵子树都有影响,相当于给整棵子树增加一个值。

    而给以某一节点 x 为根的子树增加一个权值也会影响当前子树,节点 y 所增加的值为 dis[y] * z - (dis[x] - 1) * z,每个节点都会增加 -(dis[x] - 1) * z ,

    询问时只用加上 dis[y] * y 和当前节点 y 的权值。

    给整棵子树增加一个权值可以用 dfs 序 + 线段树搞, dis 数组可以预处理出来。

    ——代码

      1 #include <cstdio>
      2 #include <cstring>
      3 #define LL long long
      4 #define root 1, 1, n
      5 #define ls now << 1, l, mid
      6 #define rs now << 1 | 1, mid + 1, r
      7 
      8 using namespace std;
      9 
     10 const int MAXN = 100001;
     11 int n, m, cnt, tot;
     12 int head[MAXN], next[MAXN << 1], to[MAXN << 1], tid[MAXN], size[MAXN];
     13 LL a[MAXN << 2], b[MAXN << 2], val[MAXN], dis[MAXN];
     14 
     15 inline void add(int x, int y)
     16 {
     17     to[cnt] = y;
     18     next[cnt] = head[x];
     19     head[x] = cnt++;
     20 } 
     21 
     22 inline void dfs(int u)
     23 {
     24     int i, v; 
     25     tid[u] = ++tot;
     26     size[u] = 1;
     27     for(i = head[u]; i != -1; i = next[i])
     28     {
     29         v = to[i];
     30         if(!size[v])
     31         {
     32             dis[v] = dis[u] + 1;
     33             dfs(v);
     34             size[u] += size[v];
     35         }
     36     }
     37 }
     38 
     39 inline void push_down(int now)
     40 {
     41     a[now << 1] += a[now];
     42     a[now << 1 | 1] += a[now];
     43     b[now << 1] += b[now];
     44     b[now << 1 | 1] += b[now];
     45     a[now] = b[now] = 0;
     46 }
     47 
     48 inline void update(LL x, LL y, int ql, int qr, int now, int l, int r)
     49 {
     50     if(ql <= l && r <= qr)
     51     {
     52         a[now] += x;
     53         b[now] += y;
     54         return;
     55     }
     56     push_down(now);
     57     int mid = (l + r) >> 1;
     58     if(ql <= mid) update(x, y, ql, qr, ls);
     59     if(mid < qr) update(x, y, ql, qr, rs);
     60 }
     61 
     62 inline LL query(int u, int x, int now, int l, int r)
     63 {
     64     if(l == r) return dis[u] * a[now] + b[now];
     65     push_down(now);
     66     int mid = (l + r) >> 1;
     67     if(x <= mid) return query(u, x, ls);
     68     else return query(u, x, rs);
     69 }
     70 
     71 int main()
     72 {
     73     int i, x, z;
     74     LL y;
     75     scanf("%d %d", &n, &m);
     76     for(i = 1; i <= n; i++)    scanf("%lld", &val[i]);
     77     memset(head, -1, sizeof(head));
     78     for(i = 1; i < n; i++)
     79     {
     80         scanf("%d %d", &x, &y);
     81         add(x, y);
     82         add(y, x);
     83     }
     84     dis[1] = 1;
     85     dfs(1);
     86     for(i = 1; i <= n; i++) update(0, val[i], tid[i], tid[i] + size[i] - 1, root);
     87     for(i = 1; i <= m; i++)
     88     {
     89         scanf("%d %d", &z, &x);
     90         if(z == 1)
     91         {
     92             scanf("%lld", &y);
     93             update(0, y, tid[x], tid[x] + size[x] - 1, root);
     94         }
     95         else if(z == 2)
     96         {
     97             scanf("%lld", &y);
     98             update(y, -((dis[x] - 1) * y), tid[x], tid[x] + size[x] - 1, root);
     99         }
    100         else printf("%lld
    ", query(x, tid[x], root));
    101     }
    102     return 0;
    103 }
    View Code
  • 相关阅读:
    C语言字母频率统计
    C语言文件操作相关函数
    【蓝桥杯】历届试题 回文数字
    【蓝桥杯】历届试题 蚂蚁感冒
    【蓝桥杯】历届试题 地宫取宝
    【蓝桥杯】历届试题 分糖果
    【蓝桥杯】历届试题 兰顿蚂蚁
    JDK的安装和配置
    【蓝桥杯】历届试题 错误票据
    【蓝桥杯】历届试题 带分数
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6811145.html
Copyright © 2011-2022 走看看