【BZOJ4034】[HAOI2015]T2【树链剖分】【线段树】

【题目链接】

之前写的,忘了发上来了。

裸树剖。

/* Footprints In The Blood Soaked Snow */
#include <cstdio>
#include <algorithm>
 
using namespace std;
 
typedef long long LL;
 
const int maxn = 100005;
 
int n, m, head[maxn], cnt, w[maxn], st[maxn], ed[maxn], size[maxn], top[maxn], son[maxn], clo, fa[maxn];
LL tr[maxn << 2], addv[maxn << 2];
 
struct _edge {
    int v, next;
} g[maxn << 1];
 
inline int iread() {
    int f = 1, x = 0; char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    return f * x;
}
 
inline void add(int u, int v) {
    g[cnt] = (_edge){v, head[u]};
    head[u] = cnt++;
}
 
inline void dfs1(int x, int f) {
    size[x] = 1; fa[x] = f;
    for(int i = head[x]; ~i; i = g[i].next) if(g[i].v ^ f) {
        dfs1(g[i].v, x);
        size[x] += size[g[i].v];
        if(size[g[i].v] > size[son[x]]) son[x] = g[i].v;
    }
}
 
inline void dfs2(int x, int tp) {
    st[x] = ++clo; top[x] = tp;
    if(son[x]) dfs2(son[x], tp);
    for(int i = head[x]; ~i; i = g[i].next) if(g[i].v ^ fa[x] && g[i].v ^ son[x])
        dfs2(g[i].v, g[i].v);
    ed[x] = clo;
}
 
inline void pushup(int p) {
    tr[p] = tr[p << 1] + tr[p << 1 | 1];
}
 
inline void pushdown(int p, int l, int mid, int r) {
    if(addv[p]) {
        addv[p << 1] += addv[p]; addv[p << 1 | 1] += addv[p];
        tr[p << 1] += addv[p] * (mid - l + 1); tr[p << 1 | 1] += addv[p] * (r - mid);
        addv[p] = 0;
    }
} 
 
inline void add(int p, int l, int r, int x, int y, LL c) {
    if(x <= l && r <= y) {
        tr[p] += c * (r - l + 1); addv[p] += c;
        return;
    }
    int mid = l + r >> 1;
    pushdown(p, l, mid, r);
    if(x <= mid) add(p << 1, l, mid, x, y, c);
    if(y > mid) add(p << 1 | 1, mid + 1, r, x, y, c);
    pushup(p);
}
 
inline LL query(int p, int l, int r, int x, int y) {
    if(x <= l && r <= y) return tr[p];
    int mid = l + r >> 1;
    pushdown(p, l, mid, r);
    LL ans = 0;
    if(x <= mid) ans += query(p << 1, l, mid, x, y);
    if(y > mid) ans += query(p << 1 | 1, mid + 1, r, x, y);
    return ans;
}
 
inline LL query(int u) {
    LL ans = 0;
    for(; u; u = fa[top[u]]) ans += query(1, 1, n, st[top[u]], st[u]);
    return ans;
}
 
int main() {
    n = iread(); m = iread();
    for(int i = 0; i <= n; i++) head[i] = -1; cnt = clo = 0;
 
    for(int i = 1; i <= n; i++) w[i] = iread();
    for(int i = 1; i < n; i++) {
        int u = iread(), v = iread();
        add(u, v); add(v, u);
    }
 
    dfs1(1, 0); dfs2(1, 1);
 
    for(int i = 1; i <= n; i++) add(1, 1, n, st[i], st[i], w[i]);
 
    while(m--) {
        int opt = iread();
        if(opt == 1) {
            int u = iread(), c = iread();
            add(1, 1, n, st[u], st[u], c);
        }
        else if(opt == 2) {
            int u = iread(), c = iread();
            add(1, 1, n, st[u], ed[u], c);
        }
        else if(opt == 3) {
            int u = iread();
            printf("%lld\n", query(u));
        }
    }
    return 0;
}
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值