HDU1166 敌兵布阵 [线段树模板]

题意:在序列中修改单点和查询区间和

复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
const int maxn=50005*4;
int sum[maxn<<2],add[maxn<<2];//sum求和,add懒惰标记
int a[maxn]={0},n=50005;//存原数组数据下标[1,n]
//更新节点信息,这里是求和
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//建树
void pushdown(int rt,int ln,int rn)
{//ln,rn为左子树,右子树的数量
    if(add[rt])//下推标记
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*ln;
        sum[rt<<1|1]+=add[rt]*rn;
        add[rt]=0;//清除本节点标记
    }
}
void build(int l,int r,int rt)//rt表示当前节点编号
{
    if(l==r)
    {
       sum[rt]=a[l];
       return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}

//点修改a[L]+=c;
//比如update(a,-b,1,n,1);//修改a点的值,减去b,当前节点区间是1到n,起始点是1
void update(int L,int c,int l,int r,int rt)
{//l,r当前节点区间,rt当前节点编号,L需要修改的节点,c修改的值
    if(l==r)
    {
        sum[rt]+=c;
        return;
    }
    int m=(l+r)>>1;
    //根据条件判断调用左子树还是右子树
    if(L<=m)
        update(L,c,l,m,rt<<1);
    else
        update(L,c,m+1,r,rt<<1|1);
    pushup(rt);//子节点更新,所以本节点也需要更新
}

//区间修改a[r,t]+=c
////比如query(a,b,1,n,1))查询a b之间的和,当前节点区间是1到n,起始点是1
void update_(int L,int R,int c,int l,int r,int rt)
{//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
    if(L<=l&&r<=R)//遍历的区间在操作区间内
    {
        sum[rt]+=c*(r-l+1);
        add[rt]+=c;
        return;
    }
    int m=(l+r)>>1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)
        update_(L,R,c,l,m,rt<<1);
    if(R>m)
        update_(L,R,c,m+1,r,rt<<1|1);
    pushup(rt);
}
//区间查询 a[l,r]的和
//下推标记函数

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1;
    pushdown(rt,m-l+1,r-m);
    int ans=0;
    if(L<=m)
        ans+=query(L,R,l,m,rt<<1);
    if(R>m)
        ans+=query(L,R,m+1,r,rt<<1|1);
    return ans;
}

int main()
{
    int t,cnt=1;
    scanf("%d",&t);
    while(t--)
    {
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        memset(add,0,sizeof(add));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
        printf("Case %d:\n",cnt++);
        char str[20];
        while(scanf("%s",str)&&str[0]!='E')
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(str[0]=='Q')
            {
                query(a,b,1,n,1);
            }
            if(str[0]=='S')
                update(a,-b,1,n,1);//修改a点的值,减去b,当前节点区间是1到n,起始点是1
            if(str[0]=='A')
                update(a,b,1,n,1);
            if(str[0]=='Q')
                printf("%d\n",query(a,b,1,n,1));//查询a b之间的和,当前节点区间是1到n,起始点是1
            
        }
    
    }
    return 0;
}
复制代码

 

posted @   付玬熙  阅读(234)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
主题色彩