贴一下WC总结里提到的那道裸题吧。。。

[bzoj4034][HAOI2015]T2

试题描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入

第一行包含两个整数 N, M 。表示点数和操作数

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

输出

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

输入示例

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

输出示例

6
9
13

数据范围

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

题解

说了是裸题。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
 
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
    if(Head == tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    return x * f;
}
 
#define maxn 100010
#define maxm 200010
#define LL long long
int n, q, m, head[maxn], next[maxm], to[maxm], V[maxn];
 
void AddEdge(int a, int b) {
    to[++m] = b; next[m] = head[a]; head[a] = m;
    swap(a, b);
    to[++m] = b; next[m] = head[a]; head[a] = m;
    return ;
}
 
int siz[maxn], fa[maxn], son[maxn], w[maxn], ww, top[maxn], val[maxn];
void dfs(int u) {
    siz[u] = 1;
    for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u]) {
        fa[to[e]] = u;
        dfs(to[e]);
        siz[u] += siz[to[e]];
        if(siz[son[u]] < siz[to[e]]) son[u] = to[e];
    }
    return ;
}
void build(int u, int tp) {
    w[u] = ++ww; top[u] = tp;
    if(son[u]) build(son[u], tp);
    for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u] && to[e] != son[u])
        build(to[e], to[e]);
    return ;
}
 
LL sumv[maxn<<2], addv[maxn<<2];
void build(int L, int R, int o) {
    if(L == R) sumv[o] = val[L];
    else {
        int M = L + R >> 1, lc = o << 1, rc = lc | 1;
        build(L, M, lc);
        build(M+1, R, rc);
        sumv[o] = sumv[lc] + sumv[rc];
    }
    return ;
}
int ql, qr;
LL v;
void update(int L, int R, int o) {
    if(ql <= L && R <= qr) addv[o] += v;
    else {
        int M = L + R >> 1, lc = o << 1, rc = lc | 1;
        if(ql <= M) update(L, M, lc);
        if(qr > M) update(M+1, R, rc);
        sumv[o] = sumv[lc] + addv[lc] * (M - L + 1);
        sumv[o] += sumv[rc] + addv[rc] * (R - M);
    }
    return ;
}
LL query(int L, int R, int o, LL Add) {
    Add += addv[o];
    if(ql <= L && R <= qr) return sumv[o] + Add * (R - L + 1);
    int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    LL ans = 0;
    if(ql <= M) ans += query(L, M, lc, Add);
    if(qr > M) ans += query(M+1, R, rc, Add);
    return ans;
}
 
LL query(int u) {
    int f = top[u]; LL ans = 0;
    while(u) {
        ql = w[f]; qr = w[u];
        ans += query(1, n, 1, 0);
        u = fa[f]; f = top[u];
    }
    return ans;
}
 
int main() {
    n = read(); q = read();
    for(int i = 1; i <= n; i++) V[i] = read();
    for(int i = 1; i < n; i++) AddEdge(read(), read());
     
    dfs(1);
    build(1, 1);
    for(int i = 1; i <= n; i++) val[w[i]] = V[i];
    build(1, n, 1);
    while(q--) {
        int tp = read(), u = read();
        if(tp == 1) {
            v = read(); ql = qr = w[u];
            update(1, n, 1);
        } else if(tp == 2) {
            v = read(); ql = w[u]; qr = ql + siz[u] - 1;
            update(1, n, 1);
        } else printf("%lld\n", query(u));
    }
     
    return 0;
}
直接贴代码吧……

 

你可能感兴趣的:(贴一下WC总结里提到的那道裸题吧。。。)