HDU 1166 排兵布阵(线段树)

题意: 第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;

每组数据最多有40000条命令

解析:本题要求实现增减、查询特定结点的数值,因此可用线段树中的单点更新算法即可。更新过后的叶子节点自动将父亲结点更新。

#include
#include
#include
#define MAX 500000
using namespace std;
int sum[MAX*2+10];
int plusnode(int root)
{
    return sum[root]=sum[root<<1]+sum[root<<1|1];
}
void buildtree(int l,int r,int root)
{
    if(l==r)
    {
        scanf("%d",&sum[root]);//初始化结点
        return;
    }
    int mid=(l+r)>>1;
    buildtree(l,mid,root<<1);
    buildtree(mid+1,r,root<<1|1);
    plusnode(root);//每次建树后自动将父节点更新为儿子结点之和
}
void update(int l,int r,int root,int p,int add)
{
    if(l==r)//为叶子节点
    {
        sum[root]+=add;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid){
        update(l,mid,root<<1,p,add);
    }
    else{
        update(mid+1,r,root<<1|1,p,add);
    }
    plusnode(root);

}
int query(int l,int r,int root,int L,int R)
{
    if(L<=l&&R>=r)//所求区间在当前区间范围内
    {
        return sum[root];
    }
    int mid=(l+r)>>1;
    int ans=0;//定义ans初始化为0,仅当查询的是叶子结点时,ans值才不会被初始化
    if(L<=mid)
    {
        ans+=query(l,mid,root<<1,L,R);
    }
    if(R>mid)
    {
        ans+=query(mid+1,r,root<<1|1,L,R);
    }
    return ans;
}
int main(){
    int T,N;
    int a,b;
    char que[10];
    scanf("%d",&T);
    for(int I=1;I<=T;I++){
        printf("Case %d:\n",I);
        scanf("%d",&N);
        buildtree(1,N,1);
        while(scanf("%s",que)&&que[0]!='E'){
            scanf("%d%d",&a,&b);
            if(que[0]=='A')
            {
                update(1,N,1,a,b);
            }
            else if(que[0]=='S')
            {
                update(1,N,1,a,-b);
            }
            else{
                int ans=query(1,N,1,a,b);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(HDU 1166 排兵布阵(线段树))