树链剖分以及模板

这里有一篇博客讲的很好

模板(以点权为主): (这个主要是树链剖分的板子, 套的其他数据结构没写)

int n, cnt, head[maxn], tim;
int dep[maxn], siz[maxn], fa[maxn];
int son[maxn], top[maxn], a[maxn];
int tid[maxn], out[maxn], pos[maxn];
struct node {
    int to, next, w;
}e[maxn<<1];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans += query_sum(1, tid[x], tid[y]);
    return ans;
}
ll get_max(int x, int y) {
    ll mx = -inf;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        mx = max(mx, query_max(1, tid[top[x]], tid[x]));
    }
    if (dep[x] > dep[y]) swap(x, y);
    mx = max(mx, query_max(1, tid[x], tid[y]));
    return mx;
}
void add_val(int x, int y, ll val) {
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, tid[top[x]], tid[x], val);
    }
    if (dep[x] > dep[y]) swap(x, y);
    update(1, tid[x], tid[y], val);
}
int get_lca(int x, int y) {
    for (;top[x] != top[y]; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
    }
    if (dep[x] > dep[y]) swap(x, y);
    return x;
}

Query on a tree
树链剖分(权值在边上)[修改某条边权, 询问树上路径的最大边权]:
(我把询问两点之间的和的函数一起加进去了,这个就当是权值在边上的综合板子吧)

注意这道题是边权转点权的经典例题,看清楚怎么处理的又有什么不同的地方

const int maxn = 1e5 + 5;
ll a[maxn];
int tid[maxn], out[maxn], pos[maxn];
struct Tree {
    int tl, tr; ll mx, lazy, val;
    void fun(ll tmp) {
        lazy = tmp;
        mx = val = tmp;
    }
}tre[maxn<<2];
void pushup(int id) {
    tre[id].mx = max(tre[id<<1].mx, tre[id<<1|1].mx);
    tre[id].val = tre[id<<1].val + tre[id<<1|1].val;
}
void pushdown(int id) {
    if(tre[id].lazy) {
        tre[id<<1].fun(tre[id].lazy);
        tre[id<<1|1].fun(tre[id].lazy);
        tre[id].lazy = 0;
    }
}
void build(int id, int l, int r) {
    tre[id].tl = l; tre[id].tr = r; tre[id].lazy = 0;
    if(l == r) {
        tre[id].mx = tre[id].val = a[pos[l]];
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int ul, int ur, ll val) {
    int l = tre[id].tl, r = tre[id].tr;
    if(ul <= l && r <= ur) {
        tre[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(ul <= mid) update(id<<1, ul, ur, val);
    if(ur > mid) update(id<<1|1, ul, ur, val);
    pushup(id);
}
ll query_max(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].mx;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_max(id<<1, ql, qr);
    else if(ql > mid) return query_max(id<<1|1, ql, qr);
    else return max(query_max(id<<1, ql, mid), query_max(id<<1|1, mid+1, qr));
}
ll query_sum(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].val;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_sum(id<<1, ql, qr);
    else if(ql > mid) return query_sum(id<<1|1, ql, qr);
    else return query_sum(id<<1, ql, mid) + query_sum(id<<1|1, mid+1, qr);
}
int n, m, cnt, head[maxn], tim;
int siz[maxn], top[maxn];
int son[maxn], dep[maxn], fa[maxn];
int dd[maxn], dis[maxn]; // 表示把那条边换到哪个点上.
struct node {
    int to, next, w, idx;
}e[maxn<<1];
void add(int u, int v, int w, int id) {
    e[cnt] = node{v, head[u], w, id};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dd[e[i].idx] = to;//把边权强制加到这条边向下的那个点上.
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_max(int x, int y) {
    ll mx = -inf;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        mx = max(mx, query_max(1, tid[top[x]], tid[x]));
    }
    if (dep[x] == dep[y]) return mx; //唯一的不同点,下面的这些代码,其他的还是一样 !!!
    if (dep[x] > dep[y]) swap(x, y);
    if (tid[son[x]] > tid[y]) swap(x, y);
    mx = max(mx, query_max(1, tid[son[x]], tid[y]));
    return mx;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
    }
    if (dep[x] == dep[y]) return ans;
    if (dep[x] > dep[y]) swap(x, y);
    if (tid[son[x]] > tid[y]) swap(x, y);
    ans += query_sum(1, tid[son[x]], tid[y]);
    return ans;
}
ll val[maxn];
void solve() {
    scanf("%d", &n); init();
    for (int i = 1 ; i < n ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w, i); add(v, u, w, i);
        val[i] = 1ll*w; //同时还要记录下每条边的权值方便下面做转化.
    }
    dfs1(1, -1, 0); dfs2(1, 1);
    for (int i = 1 ; i < n ; i ++) {
        a[dd[i]] = val[i];
    }
    build(1, 1, n);
    char op[10];
    while(1) {
        scanf("%s", op);
        if (op[0] == 'D') break;
        int l, r;
        scanf("%d%d", &l, &r);
        if (op[0] == 'Q') {
            printf("%lld\n", get_max(l, r));
        }
        else update(1, tid[dd[l]], tid[dd[l]], r);
    }
}

洛谷P3384
树链剖分(权值在点上) [区间修改(加值还要去mod) 询问区间和]:

const int maxn = 1e5 + 5;
ll a[maxn], mod;
int tid[maxn], out[maxn], pos[maxn];
struct Tree {
    int tl, tr; ll val, mx, lazy;
    void fun(ll tmp) {
        lazy = (lazy + tmp) % mod;
        val = (val + (tr - tl + 1) * tmp) % mod;
        mx = tmp;
    }
}tre[maxn<<2];
void pushup(int id) {
    tre[id].val = tre[id<<1].val+tre[id<<1|1].val;
}
void pushdown(int id) {
    if(tre[id].lazy) {
        tre[id<<1].fun(tre[id].lazy);
        tre[id<<1|1].fun(tre[id].lazy);
        tre[id].lazy = 0;
    }
}
void build(int id,int l,int r) {
    tre[id].tl = l; tre[id].tr = r; tre[id].lazy = 0;
    if(l == r) {
        tre[id].val = a[pos[l]] % mod;
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int ul, int ur, ll val) {
    int l = tre[id].tl, r = tre[id].tr;
    if(ul <= l && r <= ur) {
        tre[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(ul <= mid) update(id<<1, ul, ur, val);
    if(ur > mid) update(id<<1|1, ul, ur, val);
    pushup(id);
}
ll query_sum(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].val % mod;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_sum(id<<1, ql, qr);
    else if(ql > mid) return query_sum(id<<1|1, ql, qr);
    else return (query_sum(id<<1, ql, mid) + query_sum(id<<1|1, mid+1, qr) % mod);
}
int n, m, cnt, head[maxn], tim, rt;
int siz[maxn], top[maxn];
int son[maxn], dep[maxn], fa[maxn];
struct node {
    int to, next, w;
}e[maxn<<1];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
        ans %= mod;
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans += query_sum(1, tid[x], tid[y]);
    return ans % mod;
}
void add_val(int x, int y, ll val) {
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, tid[top[x]], tid[x], val);
    }
    if (dep[x] > dep[y]) swap(x, y);
    update(1, tid[x], tid[y], val);
}
void solve() {
    scanf("%d%d%d%lld", &n, &m, &rt, &mod);
    init();
    for (int i = 1 ; i <= n ; i ++) scanf("%lld", a+i);
    for (int i = 1 ; i < n ; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v, 1); add(v, u, 1);
    }
    dfs1(rt, -1, 0); dfs2(rt, rt); build(1, 1, n);
    while(m--) {
        int op, x, y; ll z;
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%d%lld", &x, &y, &z);
            add_val(x, y, z%mod);
        }
        else if (op == 2) {
            scanf("%d%d", &x, &y);
            printf("%lld\n", get_sum(x, y) % mod);
        }
        else if (op == 3) {
            scanf("%d%lld", &x, &z);
            update(1, tid[x], out[x], z);
        }
        else {
            scanf("%d", &x);
            printf("%lld\n", query(1, tid[x], out[x]) % mod);
        }
    }
}

BZOJ-1036
树链剖分(权值在点上)[单点修改 询问区间和/最大值]:

const int maxn = 1e5 + 5;
ll a[maxn];
int tid[maxn], out[maxn], pos[maxn];
struct Tree {
    int tl, tr; ll val, mx, lazy;
    void fun(ll tmp) {
        lazy = tmp;
        val = (tr - tl + 1) * tmp;
        mx = tmp;
    }
}tre[maxn<<2];
void pushup(int id) {
    tre[id].val = tre[id<<1].val+tre[id<<1|1].val;
    tre[id].mx = max(tre[id<<1].mx, tre[id<<1|1].mx);
}
void pushdown(int id) {
    if(tre[id].lazy) {
        tre[id<<1].fun(tre[id].lazy);
        tre[id<<1|1].fun(tre[id].lazy);
        tre[id].lazy = 0;
    }
}
void build(int id,int l,int r) {
    tre[id].tl = l; tre[id].tr = r; tre[id].lazy = 0;
    if(l == r) {
        tre[id].val = tre[id].mx = a[pos[l]];
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int ul, int ur, ll val) {
    int l = tre[id].tl, r = tre[id].tr;
    if(ul <= l && r <= ur) {
        tre[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(ul <= mid) update(id<<1, ul, ur, val);
    if(ur > mid) update(id<<1|1, ul, ur, val);
    pushup(id);
}
ll query_sum(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].val;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_sum(id<<1, ql, qr);
    else if(ql > mid) return query_sum(id<<1|1, ql, qr);
    else return query_sum(id<<1, ql, mid) + query_sum(id<<1|1, mid+1, qr);
}
ll query_max(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].mx;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_max(id<<1, ql, qr);
    else if(ql > mid) return query_max(id<<1|1, ql, qr);
    else return max(query_max(id<<1, ql, mid), query_max(id<<1|1, mid+1, qr));
}
int n, m, cnt, head[maxn], tim, rt;
int siz[maxn], top[maxn];
int son[maxn], dep[maxn], fa[maxn];
struct node {
    int to, next, w;
}e[maxn<<1];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans += query_sum(1, tid[x], tid[y]);
    return ans;
}
ll get_max(int x, int y) {
    ll mx = -inf;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        mx = max(mx, query_max(1, tid[top[x]], tid[x]));
    }
    if (dep[x] > dep[y]) swap(x, y);
    mx = max(mx, query_max(1, tid[x], tid[y]));
    return mx;
}
void add_val(int x, int y, ll val) {
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, tid[top[x]], tid[x], val);
    }
    if (dep[x] > dep[y]) swap(x, y);
    update(1, tid[x], tid[y], val);
}
int get_lca(int x, int y) {
    for (;top[x] != top[y]; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
    }
    if (dep[x] > dep[y]) swap(x, y);
    return x;
}
void solve() {
    scanf("%d", &n); init();
    for (int i = 1 ; i < n ; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v, 1); add(v, u, 1);
    }
    dfs1(1, -1, 0);
    dfs2(1, 1);
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%lld", a+i);
    }
    build(1, 1, n);
    scanf("%d", &m);
    while(m--) {
        char op[10]; int l, r;
        scanf("%s", op);
        if (!strcmp(op, "QMAX")) {
            scanf("%d%d", &l, &r);
            printf("%d\n", get_max(l, r));
        }
        else if (!strcmp(op, "QSUM")) {
            scanf("%d%d", &l, &r);
            printf("%d\n", get_sum(l, r));
        }
        else if (!strcmp(op, "CHANGE")) {
            scanf("%d%d", &l, &r);
            update(1, tid[l], tid[l], r);
        }
    }
}

bzoj - 4034
树链剖分(权值在点上)[单点/区间修改(加值) 询问区间和]:

const int maxn = 1e5 + 5;
ll a[maxn];
int tid[maxn], out[maxn], pos[maxn];
struct Tree {
    int tl, tr; ll val, lazy;
    void fun(ll tmp) {
        lazy += tmp;
        val += (tr - tl + 1) * tmp;
    }
}tre[maxn<<2];
void pushup(int id) {
    tre[id].val = tre[id<<1].val+tre[id<<1|1].val;
}
void pushdown(int id) {
    if(tre[id].lazy != 0) {
        tre[id<<1].fun(tre[id].lazy);
        tre[id<<1|1].fun(tre[id].lazy);
        tre[id].lazy = 0;
    }
}
void build(int id,int l,int r) {
    tre[id].tl = l; tre[id].tr = r; tre[id].lazy = 0;
    if(l == r) {
        tre[id].val = a[pos[l]];
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int ul, int ur, ll val) {
    int l = tre[id].tl, r = tre[id].tr;
    if(ul <= l && r <= ur) {
        tre[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(ul <= mid) update(id<<1, ul, ur, val);
    if(ur > mid) update(id<<1|1, ul, ur, val);
    pushup(id);
}
ll query_sum(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].val;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_sum(id<<1, ql, qr);
    else if(ql > mid) return query_sum(id<<1|1, ql, qr);
    else return query_sum(id<<1, ql, mid) + query_sum(id<<1|1, mid+1, qr);
}
int n, m, cnt, head[maxn], tim, rt;
int siz[maxn], top[maxn];
int son[maxn], dep[maxn], fa[maxn];
struct node {
    int to, next, w;
}e[maxn<<1];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans += query_sum(1, tid[x], tid[y]);
    return ans;
}
void add_val(int x, int y, ll val) {
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, tid[top[x]], tid[x], val);
    }
    if (dep[x] > dep[y]) swap(x, y);
    update(1, tid[x], tid[y], val);
}
void solve() {
    scanf("%d%d", &n, &m); init();
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%lld", a+i);
    }
    for (int i = 1 ; i < n ; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v, 1); add(v, u, 1);
    }
    dfs1(1, -1, 0); dfs2(1, 1); build(1, 1, n);
    while(m--) {
        int op, l, r;
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%d", &l, &r);
            update(1, tid[l], tid[l], r);
        }
        else if (op == 2) {
            scanf("%d%d", &l, &r);
            update(1, tid[l], out[l], r);
        }
        else {
            scanf("%d", &l);
            printf("%lld\n", get_sum(1, l));
        }
    }
}

bzoj - 4196
树链剖分(权值在点上)[区间修改(覆盖) 询问区间和]:

const int maxn = 1e5 + 5;
int n, cnt, head[maxn], tim;
int dep[maxn], siz[maxn], fa[maxn];
int son[maxn], top[maxn], a[maxn];
int tid[maxn], out[maxn], pos[maxn];
struct Tree {
    int tl, tr, val, lazy;
    void fun(int tmp) {
        lazy = tmp;
        val = (tr - tl + 1) * tmp;
    }
}tre[maxn<<2];
void pushup(int id) {
    tre[id].val = tre[id<<1].val+tre[id<<1|1].val;
}
void pushdown(int id) {
    if(tre[id].lazy != -1) {
        tre[id<<1].fun(tre[id].lazy);
        tre[id<<1|1].fun(tre[id].lazy);
        tre[id].lazy = -1;
    }
}
void build(int id,int l,int r) {
    tre[id].tl = l; tre[id].tr = r;
    tre[id].lazy = -1; tre[id].val = 0;
    if(l == r)  return ;
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int ul, int ur, ll val) {
    int l = tre[id].tl, r = tre[id].tr;
    if(ul <= l && r <= ur) {
        tre[id].fun(val);
        return ;
    }
    pushdown(id);
    int mid = (l+r) >> 1;
    if(ul <= mid) update(id<<1, ul, ur, val);
    if(ur > mid) update(id<<1|1, ul, ur, val);
    pushup(id);
}
ll query_sum(int id, int ql, int qr) {
    int l = tre[id].tl , r = tre[id].tr;
    if(ql <= l && r <= qr) {
        return tre[id].val;
    }
    pushdown(id);
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query_sum(id<<1, ql, qr);
    else if(ql > mid) return query_sum(id<<1|1, ql, qr);
    else return query_sum(id<<1, ql, mid) + query_sum(id<<1|1, mid+1, qr);
}
struct node {
    int to, next, w;
}e[maxn<<1];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
void init() {
    cnt = 0; Fill(head, -1);
    tim = 0; Fill(son, -1);
}
void dfs1(int u, int f, int deep) {
    dep[u] = deep + 1; siz[u] = 1;
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == f) continue;
        fa[to] = u;
        dfs1(to, u, deep+1);
        siz[u] += siz[to];
        if (son[u] == -1 || siz[to] > siz[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    tid[u] = ++tim;
    pos[tim] = u;
    if (son[u] == -1) {
        out[u] = tim;
        return ;
    }
    dfs2(son[u], tp);
    for (int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to != son[u] && to != fa[u]) {
            dfs2(to, to);
        }
    }
    out[u] = tim;
}
ll get_sum(int x, int y) {
    ll ans = 0;
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans += query_sum(1, tid[top[x]], tid[x]);
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans += query_sum(1, tid[x], tid[y]);
    return ans;
}
void add_val(int x, int y, ll val) {
    for (;top[x] != top[y] ; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(1, tid[top[x]], tid[x], val);
    }
    if (dep[x] > dep[y]) swap(x, y);
    update(1, tid[x], tid[y], val);
}
int get_lca(int x, int y) {
    for (;top[x] != top[y]; x = fa[top[x]]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
    }
    if (dep[x] > dep[y]) swap(x, y);
    return x;
}
void solve() {
    scanf("%d", &n); init();
    for (int i = 2 ; i <= n ; i ++) {
        int x; scanf("%d", &x);
        ++x; add(x, i, 1);
    }
    dfs1(1, -1, 0); dfs2(1, 1); build(1, 1, n);
    int m; scanf("%d", &m);
    while(m--) {
        char op[12]; int x;
        scanf("%s%d", op, &x); ++ x;
        if (op[0] == 'i') {
            int t1 = get_sum(1, x);
            add_val(1, x, 1);
            printf("%d\n", get_sum(1, x) - t1);
        }
        else {
            printf("%d\n", query_sum(1, tid[x], out[x]));
            update(1, tid[x], out[x], 0);
        }
    }
}

你可能感兴趣的:(树链剖分)