[BZOJ4034] [HAOI2015] T2 (树链剖分)

Description

  有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
  操作 1 :把某个节点 x 的点权增加 a 。
  操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
  操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

  第一行包含两个整数 N, M 。表示点数和操作数。
  接下来一行 N 个整数,表示树中节点的初始权值。
  接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
  再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
  作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output

  对于每个询问操作,输出该询问的答案。答案之间用换行隔开。 

Sample Input

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output

6
9
13

HINT

  对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

Source

  鸣谢bhiaibogf提供

Solution

  树链剖分,用线段树维护点权;对子树的修改就是区间修改,因为其dfs序是连续的

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 struct edge
  4 {
  5     int v, nxt;
  6 }e[200005];
  7 struct point
  8 {
  9     int val, siz, fa, son, dfn, top;
 10 }p[100005];
 11 struct seg
 12 {
 13     long long val, lazy;
 14 }a[300005];
 15 int fst[100005], ptot;
 16 
 17 void addedge(int i, int u, int v)
 18 {
 19     e[i] = (edge){v, fst[u]}, fst[u] = i;
 20 }
 21 
 22 void DFS1(int u)
 23 {
 24     p[u].siz = 1;
 25     for(int i = fst[u]; i; i = e[i].nxt)
 26         if(p[u].fa != e[i].v)
 27         {
 28             p[e[i].v].fa = u;
 29             DFS1(e[i].v);
 30             p[u].siz += p[e[i].v].siz;
 31             if(p[e[i].v].siz > p[p[u].son].siz)
 32                 p[u].son = e[i].v;
 33         }
 34 }
 35 
 36 void DFS2(int u, int top)
 37 {
 38     p[u].dfn = ++ptot, p[u].top = top;
 39     if(p[u].son) DFS2(p[u].son, top);
 40     for(int i = fst[u]; i; i = e[i].nxt)
 41         if(e[i].v != p[u].fa && e[i].v != p[u].son)
 42             DFS2(e[i].v, e[i].v);
 43 }
 44 
 45 void push_up(int o, int l, int r)
 46 {
 47     a[o].val = a[o << 1].val + a[o << 1 | 1].val;
 48     a[o].val += a[o].lazy * (r - l + 1);
 49 }
 50 
 51 void push_down(int o, int l, int r)
 52 {
 53     int mid = (l + r) >> 1;
 54     if(l == r) return;
 55     if(a[o].lazy)
 56     {
 57         a[o << 1].lazy += a[o].lazy;
 58         a[o << 1].val += a[o].lazy * (mid - l + 1);
 59         a[o << 1 | 1].lazy += a[o].lazy;
 60         a[o << 1 | 1].val += a[o].lazy * (r - mid);
 61         a[o].lazy = 0;
 62     }
 63 }
 64 
 65 void update(int o, int l, int r, int ql, int qr, int val)
 66 {
 67     int mid = (l + r) >> 1;
 68     push_down(o, l, r);
 69     if(ql <= l && r <= qr)
 70     {
 71         a[o].lazy += val;
 72         a[o].val += (long long)val * (r - l + 1);
 73         return;
 74     }
 75     if(ql <= mid) update(o << 1, l, mid, ql, qr, val);
 76     if(mid < qr) update(o << 1 | 1, mid + 1, r, ql, qr, val);
 77     push_up(o, l, r);
 78 }
 79 
 80 long long query(int o, int l, int r, int ql, int qr)
 81 {
 82     int mid = (l + r) >> 1;
 83     long long ans = 0;
 84     push_down(o, l, r);
 85     if(ql <= l && r <= qr) return a[o].val;
 86     if(ql <= mid) ans = query(o << 1, l, mid, ql, qr);
 87     if(mid < qr) ans += query(o << 1 | 1, mid + 1, r, ql, qr);
 88     return ans;
 89 }
 90 
 91 int main()
 92 {
 93     int n, m, u, v, op, x, val;
 94     long long ans;
 95     scanf("%d%d", &n, &m);
 96     for(int i = 1; i <= n; ++i)
 97         scanf("%d", &p[i].val);
 98     for(int i = 1; i < n; ++i)
 99     {
100         scanf("%d%d", &u, &v);
101         addedge(i << 1, u, v);
102         addedge(i << 1 | 1, v, u);
103     }
104     DFS1(1), DFS2(1, 1);
105     for(int i = 1; i <= n; ++i)
106         update(1, 1, n, p[i].dfn, p[i].dfn, p[i].val);
107     while(m--)
108     {
109         scanf("%d", &op);
110         if(op == 1)
111         {
112             scanf("%d%d", &x, &val);
113             update(1, 1, n, p[x].dfn, p[x].dfn, val);
114         }
115         else if(op == 2)
116         {
117             scanf("%d%d", &x, &val);
118             update(1, 1, n, p[x].dfn, p[x].dfn + p[x].siz - 1, val);
119         }
120         else
121         {
122             scanf("%d", &x);
123             ans = 0;
124             while(x)
125             {
126                 ans += query(1, 1, n, p[p[x].top].dfn, p[x].dfn);
127                 x = p[p[x].top].fa;
128             }
129             printf("%lld\n", ans);
130         }
131     }
132     return 0;
133 }
View Code

 

posted @ 2016-06-27 10:12  CtrlCV  阅读(130)  评论(0编辑  收藏  举报