hdu 3966 Aragorn's Story(树链剖分+区间修改+单点查询)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:给一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

D C1 C2 K:把C1与C2的路径上的所有点权值减去K

Q C:查询节点编号为C的权值

题解:就是树链剖分具体看代码,还有注释。

#include <iostream>
#include <cstring>
using namespace std;
const int M = 5e4 + 10;
struct Edge {
    int v , next , w;
}edge[M << 1];
int head[M] , e;//链式前向星存边
int top[M];//重链的根节点
int fa[M];//fa[i]表示i的父节点
int deep[M];//节点的深度
int num[M];//num[i]表示i节点子树一共有多少节点
int p[M];//p[i]表示i点在线段树中的位置
int fp[M];//fp[i]表示线段树中位置为i的节点是什么
int son[M];//sum[u]表示u点的重儿子
int pos;
void init() {
    memset(head , -1 , sizeof(head));
    memset(son , -1 , sizeof(son));
    e = 0;
    pos = 1;
}//初始化
void add(int u , int v) {
    edge[e].v = v;
    edge[e].next = head[u];
    head[u] = e++;
}//加边
void dfs1(int u , int pre , int d) {
    deep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for(int i = head[u] ; i != -1 ; i = edge[i].next) {
        int v = edge[i].v;
        if(v != pre) {
            dfs1(v , u , d + 1);
            num[u] += num[v];
            if(son[u] == -1 || num[v] > num[son[u]]) {
                son[u] = v;
            }
        }
    }
}//寻找重点
void getpos(int u , int sp) {
    top[u] = sp;
    p[u] = pos++;
    fp[pos - 1] = u;
    if(son[u] == -1)
        return ;
    getpos(son[u] , sp);
    for(int i = head[u] ; i != -1 ; i = edge[i].next) {
        int v = edge[i].v;
        if(v != son[u] && v != fa[u]) {
            getpos(v , v);
        }
    }
}//构建重链
struct TnT {
    int l , r , sum , lazy;
}T[M << 2];
int a[M];
void build(int l , int r , int i) {
    int mid = (l + r) >> 1;
    T[i].l = l , T[i].r = r , T[i].lazy = 0 , T[i].sum = 0;
    if(T[i].l == T[i].r) {
        T[i].sum = a[fp[l]];
        return ;
    }
    build(l , mid , i << 1);
    build(mid + 1 , r , (i << 1) | 1);
    T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
}
void pushdown(int i) {
    if(T[i].lazy) {
        T[i << 1].sum += T[i].lazy * (T[i << 1].r - T[i << 1].l + 1);
        T[(i << 1) | 1].sum += T[i].lazy * (T[(i << 1) | 1].r - T[(i << 1) | 1].l + 1);
        T[i << 1].lazy += T[i].lazy;
        T[(i << 1) | 1].lazy += T[i].lazy;
        T[i].lazy = 0;
    }
}
void updata(int l , int r , int ad , int i) {
    int mid = (T[i].l + T[i].r) >> 1;
    if(T[i].l == l && T[i].r == r) {
        T[i].sum += ad * (r - l + 1);
        T[i].lazy += ad;
        return ;
    }
    pushdown(i);
    if(mid < l) {
        updata(l , r , ad , (i << 1) | 1);
    }
    else if(mid >= r) {
        updata(l , r , ad , i << 1);
    }
    else {
        updata(l , mid , ad , i << 1) , updata(mid + 1 , r , ad , (i << 1) | 1);
    }
    T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
}
int query(int i , int pos) {
    int mid = (T[i].l + T[i].r) >> 1;
    if(T[i].l == pos && T[i].r == pos) {
        return T[i].sum;
    }
    pushdown(i);
    T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
    if(mid < pos) {
        return query((i << 1) | 1 , pos);
    }
    else {
        return query(i << 1 , pos);
    }
}
void change(int u , int v , int ad) {
    int f1 = top[u] , f2 = top[v];
    while(f1 != f2) {
        if(deep[f1] < deep[f2]) {
            swap(f1 , f2);
            swap(u , v);
        }
        updata(p[f1] , p[u] , ad , 1);
        u = fa[f1] , f1 = top[u];
    }
    if(deep[u] < deep[v])
        swap(u , v);
    updata(p[v] , p[u] , ad , 1);
}//树链剖分特别的更新方法,类似于lca从各子链上查询直到到了同一条重链上自行理解一下。
int main() {
    int n , m , q , x , y , z;
    while(scanf("%d%d%d" , &n , &m , &q) != EOF) {
        init();
        for(int i = 1 ; i <= n ; i++) {
            scanf("%d" , &a[i]);
        }
        for(int i = 0 ; i < m ; i++) {
            scanf("%d%d" , &x , &y);
            add(x , y);
            add(y , x);
        }
        dfs1(1 , 0 , 0);
        getpos(1 , 1);
        char cp[5];
        build(0 , pos + 1 , 1);
        while(q--) {
            scanf("%s" , cp);
            if(cp[0] == 'I') {
                scanf("%d%d%d" , &x , &y , &z);
                change(x , y , z);
            }
            if(cp[0] == 'D') {
                scanf("%d%d%d" , &x , &y , &z);
                change(x , y , -z);
            }
            if(cp[0] == 'Q') {
                scanf("%d" , &x);
                printf("%d
" , query(1 , p[x]));
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/6766200.html