HDU3966(树链剖分)

题目:Aragorn’s Story

题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值

分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可。
转载:HDU3966(树链剖分)
个人觉得原博主PushUp函数处的sum[]更改有些奇怪并进行了修改,虽然对这道题的结果没有影响,不过sum[]对这道题来说其实是多余的

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 5e4 + 10;
int n, m, Q;
int tim;

int num[maxn], siz[maxn], top[maxn], son[maxn];
int dep[maxn], tid[maxn], rak[maxn], fa[maxn];
int head[maxn], to[2*maxn], nex[2*maxn], edge;

void Init(){
    memset(head, -1, sizeof(head));
    memset(son, -1, sizeof(son));
    tim = 0;
    edge = 0;
}

void addedge(int u, int v){
    to[edge] = v, nex[edge] = head[u], head[u] = edge++;
    to[edge] = u, nex[edge] = head[v], head[v] = edge++;
}

void dfs1(int u, int father, int d){
    dep[u] = d;
    fa[u] = father;
    siz[u] = 1;
    for(int i = head[u]; ~i; i = nex[i]){
        int v = to[i];
        if(v != father){
            dfs1(v, u, d+1);
            siz[u] += siz[v];
            if(!~son[u] || siz[v] > siz[son[u]]){
                son[u] = v;
            }
        }
    }
}

void dfs2(int u, int tp){
    top[u] = tp;
    tid[u] = ++tim;
    rak[tid[u]] = u;
    if(son[u]==-1) return;
    dfs2(son[u], tp);
    for(int i = head[u]; ~i; i = nex[i]){
        int v = to[i];
        if(v != son[u] && v!=fa[u]){
            dfs2(v, v);
        }
    }
}
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1

int sum[maxn<<2], col[maxn<<2];

void PushUp(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void PushDown(int rt, int m){
    if(col[rt]){
        col[rt<<1] += col[rt];
        col[rt<<1|1] += col[rt];
        sum[rt<<1] += (m-(m>>1))*col[rt];
        sum[rt<<1|1] += (m>>1)*col[rt];
        col[rt] = 0;
    }
}

void Build(int l, int r, int rt){
    col[rt] = 0;
    if(l == r){
        sum[rt] = num[rak[l]];
        return;
    }
    int mid = (l+r)>>1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

void Update(int L, int R, int v, int l, int r, int rt){
    if(L<=l && R >= r){
        col[rt] += v;
        sum[rt] += v*(r-l+1);
        return;
    }
    PushDown(rt, r-l+1);
    int mid = (l+r)>>1;
    if(L<=mid)
        Update(L, R, v, lson);
    if(R>mid)
        Update(L, R, v, rson);
    PushUp(rt);
}

int Query(int l, int r, int rt, int val){
    if(l == r)
        return sum[rt];
    PushDown(rt, r-l+1);
    int mid = (l+r)>>1;
    int ret = 0;
    if(val <= mid) ret = Query(lson, val);
    else ret = Query(rson, val);
    PushUp(rt);
    return ret;
}

void Change(int x, int y, int val){
    while(top[x]!=top[y]){
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        Update(tid[top[x]], tid[x], val, 1, n, 1);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    Update(tid[x], tid[y], val, 1, n, 1);
}


int main(){
    char op[5];
    int a, b, c;
    while(~scanf("%d%d%d", &n, &m, &Q)){
        Init();
        for(int i = 1; i <= n; ++ i){
            scanf("%d", num+i);
        }
        for(int i = 1; i <= m; ++ i){
            scanf("%d%d", &a, &b);
            addedge(a, b);
        }
        dfs1(1, 0, 0);
        dfs2(1, 1);
        Build(1, n, 1);
        while(Q--){
            scanf("%s", op);
            if(op[0] == 'Q'){
                scanf("%d", &a);
                printf("%d\n", Query(1, n, 1, tid[a]));
            }else{
                scanf("%d%d%d", &a, &b, &c);
                if(op[0] == 'D') c = -c;
                Change(a, b, c);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值