BZOJ 4034: [HAOI2015]树上操作

来源:互联网 发布:爱赚网是什么软件 编辑:程序博客网 时间:2024/05/24 06:06

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 。

分析

我们注意到,对于一颗树而言,对他进行树剖之后呢,根于其子树的编号一定是连续的,那么我们就可以愉快的树剖了

代码

#include <bits/stdc++.h>#define N 1000005#define ll long longint read(){    int x = 0, f = 1;    char ch = getchar();    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}    return x * f;}struct NOTE{    int to,next;}e[N << 1];int cnt;int next[N];void insert(int x,int y){    e[++cnt] = (NOTE){y, next[x]}; next[x] = cnt;    e[++cnt] = (NOTE){x, next[y]}; next[y] = cnt;}struct TREE{    ll sum;    ll lazy;}t[N];int n,m;int top[N];int fa[N],son[N];int dep[N],size[N];int pos[N],mx[N],pre[N];void dfs1(int x,int d,int f){    dep[x] = d;    fa[x] = f;    size[x] = 1;    for (int i = next[x]; i; i = e[i].next)    {        int v = e[i].to;        if (v == f)            continue;        dfs1(v, d + 1, x);        size[x] += size[v];        if (!son[x] || size[v] > size[son[x]])            son[x] = v;    }}int tot;void dfs2(int x,int k){    top[x] = k;    pos[x] = ++tot;    mx[x] = tot;    pre[pos[x]] = x;    if (!son[x])        return;    dfs2(son[x],k);    mx[x] = std::max(mx[x], mx[son[x]]);    for (int i = next[x]; i; i = e[i].next)    {        int v = e[i].to;        if (v != son[x] && v != fa[x])        {            dfs2(e[i].to, e[i].to);            mx[x] = std::max(mx[x], mx[v]);        }    }}void pushDown(int l,int r,int p){    if (l == r)        return ;    int mid = (l + r) >> 1;    ll tmp = t[p].lazy;    t[p].lazy = 0;    t[p * 2].lazy += tmp, t[p * 2 + 1].lazy += tmp;    t[p * 2].sum += tmp * (mid - l + 1);    t[p * 2 + 1].sum += tmp * (r - mid);}void add(int p,int l,int r,int x,int y,ll val){    if (t[p].lazy)        pushDown(l,r,p);    if (l == x && y == r)    {        t[p].lazy += val;        t[p].sum += val * (r - l + 1);        return;    }    int mid = (l + r) >> 1;    if (x <= mid)        add(p * 2, l, mid, x, std::min(y, mid), val);    if (y > mid)        add(p * 2 + 1, mid + 1, r, std::max(mid + 1, x), y, val);    t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;}ll query(int p,int l,int r,int x,int y){    if (t[p].lazy)        pushDown(l,r,p);    if (l == x && r == y)        return t[p].sum;    int mid = (l + r) >> 1;    ll ans = 0;    if (x <= mid)        ans += query(p * 2, l, mid, x, std::min(mid, y));    if (y > mid)        ans += query(p * 2 + 1, mid + 1, r, std::max(mid + 1, x), y);    return ans;}ll Query(int x){    ll ans = 0;    while (top[x] != 1)    {        ans += query(1, 1, n, pos[top[x]], pos[x]);        x = fa[top[x]];    }    ans += query(1, 1, n, 1, pos[x]);    return ans;}int v[N];int main(){    n = read(), m = read();    for (int i = 1; i <= n; i++)        v[i] = read();    for (int i = 1; i < n; i++)    {        int x = read(), y = read();        insert(x,y);    }    dfs1(1,1,0);    dfs2(1,1);    for (int i = 1; i <= n; i++)        add(1, 1, n, pos[i], pos[i], v[i]);    int opt,x,a;    for (int i = 1; i <= m; i++)    {        opt = read();        x = read();        if (opt == 1)        {            a = read();            add(1 , 1, n, pos[x], pos[x], a);        }        if (opt == 2)        {            a = read();            add(1 , 1, n, pos[x], mx[x], a);        }        if (opt == 3)            printf("%lld\n",Query(x));    }}
0 0
原创粉丝点击