线段树-区间和-敌兵布阵(曾老代码)

//HDU1166-线段树模板(区间和):曾贵胜
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define N 50005
using namespace std;


int num[N];


struct Tree
{
    int l;    //左端点 
    int r;    //右端点 
    int sum;  //总数 
}tree[N*4];   //总线段长度为N,若开数组,一般开到N的4倍 


void build(int root,int l,int r)  //建立线段树:root为根节点,它的区间为[l,r] 
{
    tree[root].l=l;
    tree[root].r=r;
    if(tree[root].l==tree[root].r)  //当左右端点相等时就是叶子节点 
    {
     tree[root].sum=num[l];      //赋初值 
   return;                     //递归出口 
    }
    int mid=(l+r)/2;
    build(root<<1,l,mid);           //root<<1 相当于root*2 ,即它的左孩子 
    build(root<<1|1,mid+1,r);       //root<<1|1 相当于root*2+1 ,即它的右孩子 
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;  //父亲的sum=左孩子的sum+右孩子的sum 
}


void update(int root,int pos,int val)  //更新:root是根节点,pos和val表示将在pos点的值更新为val 
{
    if(tree[root].l==tree[root].r)     //如果是叶子节点,即是pos对应的位置 
    {
     tree[root].sum=val;            //更新操作 
   return;                        //递归出口 
    }
    int mid=(tree[root].l+tree[root].r)/2;
    if(pos<=mid)                              //如果pos点是root对应的左孩子 
        update(root<<1,pos,val);              //在左孩子里面找 
    else
        update(root<<1|1,pos,val);            //在右孩子里面找
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;  //父亲的sum=左孩子的sum+右孩子的sum 
}

int query(int root,int L,int R)              //查询:root为根节点,[L,R]表示要查询的区间 
{
    if(L<=tree[root].l && R>=tree[root].r)   //如果要查询的区间[L,R]包含root节点表示的区间 
   return tree[root].sum;               //直接返回root节点的sum值 
    int mid=(tree[root].l+tree[root].r)/2;   
int ret=0;
    if(L<=mid) ret+=query(root<<1,L,R);    //查询root节点的左孩子 
    if(R>mid)  ret+=query(root<<1|1,L,R);  //查询root节点的右孩子 
    return ret;                            //返回查询结果 
}


int main()
{
    //freopen("hdu1166.in","r",stdin);
    //freopen("hdu1166.out","w",stdout);
    
    int T,n,a,b;
    char str[10];
    scanf("%d", &T);                 //数据组数
    for(int cas=1;cas<=T;cas++) 
    {
    scanf("%d", &n);
for(int i=1;i<=n;i++) 
            scanf("%d", &num[i]);    //在i点的兵力数量 
        build(1,1,n);                //从根节点1开始构建线段树,区间[1,n] 
        printf("Case %d:\n",cas);
        while(scanf("%s",str),strcmp(str,"End"))
        {
        scanf("%d%d",&a,&b);
        if(strcmp(str,"Query")==0)         //也可写成 if(str[0]=='Q')   
        {
           if(a>b) swap(a,b);             //查询区间[a,b] 
           printf("%d\n",query(1,a,b));   //输出查询结果 
}
if(strcmp(str,"Add")==0)           //也可写成 if(str[0]=='A')   
        {
           num[a]=num[a]+b;               //增加 
           update(1,a,num[a]);            //更新a点的值为num[a] 
}
if(strcmp(str,"Sub")==0)           //也可写成 if(str[0]=='S')   
        {
           num[a]=num[a]-b;               //减少 
           update(1,a,num[a]);            //更新a点的值为num[a] 
}
        }
    }     
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值