HDU 1166 排兵布阵(线段树)

来源:互联网 发布:瑞安司法淘宝网拍卖 编辑:程序博客网 时间:2024/04/27 22:44
题意:第一行一个整数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<iostream>#include<cstdio>#include<cstring>#define MAX 500000using 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;}

0 0
原创粉丝点击