NYOJ 116 士兵杀敌(二) (线段树区间求和)

题目链接:NYOJ 116 士兵杀敌(二)

       这一个是线段树的入门级水题,本题要求我们给出某个区间的区间和。这个问题和线段树的单点更新还是基本一致的。只要把单点更新中的值覆盖变为值得叠加,这一题便可以轻松解决了。如果不知道线段树的单点更新,请移步:传送门

【代码如下】

#include <stdio.h>
#include <string.h>
#define MAXN 1<<21  //lg100000 约等于 21
typedef struct{
    int left,right;    
    int sum_kill;      //杀人数 
}Soldier;
Soldier node[MAXN];    
int father[MAXN>>1];
void build(int i,int left,int right){
    node[i].left = left;
    node[i].right = right;
    node[i].sum_kill = 0;
    if(left == right){
        father[left] = i;
        return ;
    }
    build(i<<1,left,(left+right)/2);
    build(2*i+1,1+(left+right)/2,right);
    return ;
}
void Updata(int ri){
    if(ri == 1) return ;
    int fa = ri/2;
    //只要将单点问题的这里变成,下边这样就可以了,不明白的可以想想为什么
    node[fa].sum_kill = node[2*fa].sum_kill + node[2*fa+1].sum_kill;
    Updata(fa);
}
int SK;
void Query(int i,int left,int right){
    if(node[i].left == left && node[i].right == right){
        //这里也是一个和单点问题有区别的 地方 ,把原先单点更新问题中的值覆盖,变为了叠加
        SK += node[i].sum_kill;
        return ;
    }
    if(left <= node[2*i].right){
        if( right <= node[2*i].right )
            Query(2*i,left,right);
        else
            Query(2*i,left,node[2*i].right);
    }
    if(right >= node[2*i+1].left){
        if(left >= node[2*i+1].left)
            Query(2*i+1,left,right);
        else
            Query(2*i+1,node[2*i+1].left,right);
    }
    return ;
}

int main(){
    char op[10];
    int a,b,i;
    int N,M,tmp_kill;
    scanf("%d%d",&N,&M);
    build(1,1,N);
    for(i = 1; i <= N; i++){
        scanf("%d",&tmp_kill);
        node[father[i]].sum_kill += tmp_kill;
        Updata(father[i]);
    }
    while(M--){
        getchar();
        scanf("%s",op);
        SK = 0;
        if(!strcmp(op,"QUERY")){
            scanf("%d%d",&a,&b);
            Query(1,a,b);
            printf("%d\n",SK);
        }else if(!strcmp(op,"ADD")){
            scanf("%d%d",&a,&b);
            node[father[a]].sum_kill += b;
            Updata(father[a]);
        }
    }
    return 0;
}
(如有错误,欢迎指正,转载请注明出处)


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值