[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\n", query(x, tid[x], root));
101     }
102     return 0;
103 }
View Code

 

posted @ 2017-05-05 08:38  zht467  阅读(128)  评论(0编辑  收藏  举报