BZOJ 4034[HAOI2015]树上操作 树链剖分

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

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

题解:刷水有益健康...

#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin), freopen(s".out","w",stdout)  
#define maxn 110000 
#define ll long long 
#define lson (x<<1)
#define rson ((x<<1)|1)
using namespace std;
int hd[maxn], to[maxn << 1], nex[maxn << 1], st[maxn], ed[maxn]; 
int fa[maxn], dep[maxn], dfn[maxn], ln[maxn], hson[maxn], siz[maxn], bot[maxn], top[maxn];  
int edges, n , Q, tim; 
ll val[maxn]; 
void add(int u, int v)
{
    nex[++edges] = hd[u], hd[u] = edges, to[edges] = v; 
}  
void dfs1(int u, int ff)
{
    fa[u] = ff, dep[u] = dep[ff] + 1, siz[u] = 1; 
    for(int i = hd[u]; i ; i = nex[i])
    {
        int v = to[i]; 
        if(v == ff) continue; 
        dfs1(v, u); 
        siz[u] += siz[v]; 
        if(siz[v] > siz[hson[u]]) hson[u] = v; 
    }
}
void dfs2(int u, int tp)
{
    top[u] = tp, ln[++tim] = u, dfn[u] = tim, st[u] = tim; 
    if(hson[u]) 
        dfs2(hson[u], tp), bot[u] = bot[hson[u]]; 
    else 
        bot[u] = u; 
    for(int i = hd[u]; i ; i = nex[i])
    {
        int v = to[i]; 
        if(v == fa[u] || v == hson[u]) continue; 
        dfs2(v, v); 
    }
    ed[u] = tim; 
}
struct Node
{
    ll lazy, val, sumv;  
}t[maxn << 3]; 
void mark(int l, int r, int x, ll d)
{
    t[x].lazy += d; 
    ll tmp = r - l + 1; 
    t[x].sumv += 1ll*tmp*1ll*d;       
}
void pushdown(int l, int r, int x)
{ 
    if(!t[x].lazy) return; 
    int mid = (l + r) >> 1; 
    if(mid >= l) mark(l, mid, lson, t[x].lazy); 
    if(r > mid)  mark(mid + 1, r, rson, t[x].lazy); 
    t[x].lazy = 0; 
}
void build(int l, int r, int x)
{
    if(l == r)
    {
        t[x].sumv = t[x].val = val[ln[l]]; 
        return; 
    }
    int mid = (l + r) >> 1; 
    build(l, mid, lson); 
    build(mid + 1, r, rson); 
    t[x].sumv = t[lson].sumv + t[rson].sumv; 
}
void update(int l, int r, int x, int L, int R, ll d)
{
    pushdown(l, r, x); 
    if(l >= L && r <= R) 
    {
        mark(l, r, x, d); 
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) update(l, mid, lson, L, R, d); 
    if(R > mid) update(mid + 1, r, rson, L, R, d); 
    t[x].sumv = t[lson].sumv + t[rson].sumv; 
}
ll query(int l, int r, int x, int L, int R)
{
    pushdown(l, r, x); 
    if(l >= L && r <= R) return t[x].sumv; 
    int mid = (l + r) >> 1; 
    ll tmp = 0;
    if(L <= mid) tmp += query(l, mid, lson, L, R); 
    if(R > mid) tmp += query(mid + 1, r, rson, L, R); 
    return tmp;  
}
void modify1(int x, ll d)
{
    update(1, n, 1, dfn[x], dfn[x], d); 
}
void modify2(int x, ll d)
{
    update(1, n, 1, st[x], ed[x], d); 
}
ll Query(int x)
{
    ll tmp = 0; 
    while(x) 
    {
        tmp += query(1, n, 1, dfn[top[x]], dfn[x]); 
        x = fa[top[x]]; 
    }
    return tmp; 
}
int main()
{
    // setIO("input"); 
    scanf("%d%d",&n,&Q); 
    for(int i = 1;i <= n; ++i) scanf("%lld",&val[i]); 
    for(int i = 1, u , v; i < n; ++i) 
    {
        scanf("%d%d",&u,&v), add(u, v), add(v, u); 
    }
    dfs1(1, 0), dfs2(1, 1), build(1, n, 1); 
    while(Q--)
    {
        int opt, x; 
        ll a; 
        scanf("%d",&opt); 
        if(opt == 1)
        {
            scanf("%d%lld",&x,&a), modify1(x, a); 
        }
        if(opt == 2)
        {
            scanf("%d%lld",&x,&a), modify2(x, a); 
        }
        if(opt == 3)
        { 
            scanf("%d",&x); 
            printf("%lld\n",Query(x)); 
        }
    }
    return 0; 
}

  

posted @ 2019-06-05 20:16  EM-LGH  阅读(168)  评论(0编辑  收藏  举报