树的区间查询与更新(线段树)

原题:http://oj.51isoft.com/bnuoj/problem_show.php?pid=14223

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>
#include <math.h>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
#define CLR(x) memset(x,0,sizeof(x))
#define LL long long
#define typec double
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
const int N = 100000;
LL add[N<<2];
LL sum[N<<2];
void PushUp(int rt){
    sum[rt]=sum[rt << 1] + sum[rt<<1 | 1];
}
void PushDown(int rt,int m){
    if (add[rt]){
        add[rt<<1]+=add[rt];
        add[rt<<1 | 1]+=add[rt];
        sum[rt<<1] += (add[rt] * (m-(m>>1)));
        sum[rt<<1 | 1]+=add[rt]*(m>>1);
        add[rt]=0;
    }
}
void build(int l,int r,int rt){
    add[rt]=0;
    if (l==r){
        sum[rt]=0;
        return;
    }
    int m=(l + r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
LL ans[N];
void output(int l,int r,int rt){
    if (l==r){
        ans[l]=sum[rt];
        return;
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    output(lson);
    output(rson);
    PushUp(rt);
}
void update(int L ,int R,LL c,int l,int r,int rt){
    if (L<=l && r<=R){
        add[rt]+=c;
        sum[rt]+=c*(r-l+1LL);
        return;
    }
    PushDown(rt,r-l+1);
    int m=(l + r)>>1;
    if (L<=m) update(L,R,c,lson);
    if (m<R) update(L,R,c,rson);
    PushUp(rt);
}
LL query(int L ,int R ,int l ,int r ,int rt){
    if (L<=l && r<=R)
        return sum[rt];
    PushDown(rt,r-l+1);
    int m=(l + r)>>1;
    LL ret=0;
    if (L<=m) ret+=query(L,R,lson);
    if (m<R) ret+=query(L,R,rson);
    return ret;
}
LL pay[N];
int n,m;
char str[100];
int head[N],tot;
int order[N][2],o;
struct E{
    int to,next;
}edge[N];
void addedge(int a,int b){
    edge[tot].to=b;
    edge[tot].next=head[a];
    head[a]=tot++;
}
int dfs(int x){
    order[x][0]=++o;order[x][1]=o;
    for (int i=head[x];i!=-1;i=edge[i].next){
        int temp=dfs(edge[i].to);
        order[x][1]=temp;
    }
    return order[x][1];
}
void solve(){
    memset(head,-1,sizeof(head));
    tot=0;
    for (int i=1;i<n;++i){
        int temp;
        scanf("%d%lld",&temp,&pay[i]);
        addedge(temp,i);
    }
    o=0;
    dfs(0);
    build(1,n,1);
    for (int i=0;i<n;++i)
        update(order[i][0],order[i][0],pay[i],1,n,1);
    while(m--){
        int a;LL b,c;
        scanf("%s%d%lld%lld",str,&a,&b,&c);
        if (str[0]=='e'){
            LL res=query(order[a][0],order[a][0],1,n,1);
            if (res<b) update(order[a][0],order[a][0],c,1,n,1);
        }
        else{
            LL res=query(order[a][0],order[a][1],1,n,1);
            if (res<b*(order[a][1]-order[a][0]+1LL)) update(order[a][0],order[a][1],c,1,n,1);
        }
    }
    output(1,n,1);
    for (int i=0;i<n;++i)
        printf("%lld\n",ans[order[i][0]]);
}
int main(){
   // freopen("in","r",stdin);
    while (~scanf("%d%d%lld",&n,&m,&pay[0])) solve();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值