线段树—区间更新 HDU4267 A Simple Problem With Integers

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31829

思路:线段树。主要是学习一下线段树的区间更新。

描述一下区间更新的方法。查询当前区间是否在要更新的区间内,若在,标记add值为更新值;不在,把要更新区间按照已有线段树的分割方法分割然后向下传递。查询的时候,如果为单点,把单点的值更新为sum+addadd=0;若为区间,返回sum+(R-L+1)*add,不对sum值作处理。

叙述起来是这么的轻松,第一次做却异常艰难。首先是update函数的边界控制,然后是更新区间和更新点值的方法,最后因为query往下传递add时没开成long long又错了一段时间。。。。

源码:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

typedef long long ll;

int const MAXN = 100000;

ll sum[MAXN<<2];

ll add[MAXN<<2];

int n,m;

int gmax(int a,int b){return a>b?a:b;}

int gmin(int a,int b){return a<b?a:b;}

void build(int mark,ll now,int L,int R,int st)

{

    if(L==R){

        sum[st] = now;

        return;

    }

    int mid = (L+R)>>1;

    if(mid>=mark)   build(mark,now,L,mid,st<<1);

    else            build(mark,now,mid+1,R,(st<<1)+1);

    sum[st] = sum[st<<1] + sum[(st<<1)+1];

}

void maintain(int L, int R,int st)

{

//    printf("L = %d, R = %d,st = %d\n",L,R,st);

    if(L==R){

        sum[st] = sum[st] + add[st];

        add[st] = 0;

    }

    else

        sum[st] = sum[st<<1] + sum[(st<<1)+1] + add[st]*(R-L+1);

    return;

}

void update(int l,int r,ll now,int L,int R,int st)

{

    if(l<=L && r>=R){

//        printf("L = %d,R = %d,st = %d,sum = %d\n",L,R,st,sum[st]);

        add[st] += now;

        maintain(L,R,st);

        return;

    }

    int mid = (L+R)>>1;

    if(mid<l)   update(l,r,now,mid+1,R,(st<<1)+1);

    else if(mid>=r) update(l,r,now,L,mid,(st<<1));

    else{

        if(mid>=l)  update(l,r,now,L,mid,st<<1);   /// else    maintain(l,mid,st<<1);

        if(mid<R)   update(l,r,now,mid+1,R,(st<<1)+1);///  else    maintain(mid+1,R,(st<<1)+1);

    }

    maintain(L,R,st);

}

ll query(int l,int r,int L,int R,int st,ll aa)

{

//    printf("L = %d,R = %d,st = %d\n",L,R,st);

    if(l<=L && r>=R){

//        printf("sum = %d,st = %d\n",sum[st],st);

        return sum[st]+aa*(R-L+1);

    }

    int mid = (L+R)>>1;

    ll ans = 0;

    if(mid>=l)  ans += query(l,r,L,mid,st<<1,aa+add[st]);

    if(mid<r)   ans += query(l,r,mid+1,R,(st<<1)+1,aa+add[st]);

    return ans;

}

int main()

{

    scanf("%d%d",&n,&m);

    int a,b;

    ll t,c;

    memset(sum,0,sizeof(sum));

    memset(add,0,sizeof(add));

    for(int i=1; i<=n; i++){

        scanf("%I64d",&t);

        build(i,t,1,n,1);

    }

//    for(int i=1; i<(n<<2); i++)

//        printf("%02d ",i);

//    printf("\n");

//    for(int i=1; i<=(n<<2); i++)

//                printf("%02I64d ",sum[i]);

//            printf("\n");

    char temp[5];

    for(int i=0; i<m; i++){

        scanf("%s%d%d",temp,&a,&b);

        if(temp[0]=='Q')    printf("%I64d\n",query(a,b,1,n,1,add[1]));

        if(temp[0]=='C'){

            scanf("%I64d",&c);

            update(a,b,c,1,n,1);

//            for(int i=1; i<=(n<<2); i++)

//                printf("%02I64d ",sum[i]);

//            printf("\n");

//            for(int i=1; i<=(n<<2); i++)

//                printf("%02d ",add[i]);

//            printf("\n");

//            for(int i=1; i<=(n<<2); i++)

//                printf("%02I64d ",sum[i]);

//            printf("\n");

        }

    }

    return 0;

}/*

10 6

1 2 3 4 5 6 7 8 9 10

Q 4 4

Q 1 10

C 3 6 3

C 3 6 -3

C 4 6 -3

Q 2 4

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值