poj3468(线段树||树状数组)

//成段更新线段树即可
#include <iostream>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "algorithm"
#include <queue>
#define N 100005
using namespace std;

struct node {
    long long int data,lazy;
    int left,right;
}ss[N<<2];

void pushdown(int k,int len)
{
    if(ss[k].lazy)
    {
        ss[k<<1].lazy+=ss[k].lazy;
        ss[k<<1|1].lazy+=ss[k].lazy;
        ss[k<<1].data+=ss[k].lazy*(len-(len>>1));
        ss[k<<1|1].data+=ss[k].lazy*(len>>1);
        ss[k].lazy=0;
    }
}

void buildtree(int k,int l,int r)
{
    ss[k].lazy=0;
    ss[k].left=l;ss[k].right=r;
    if(l==r) {
        scanf("%lld",&ss[k].data);
        return;
    }
    int mid=(l+r)>>1;
    buildtree(k<<1,l,mid);
    buildtree(k<<1|1,mid+1,r);
    ss[k].data=ss[k<<1].data+ss[k<<1|1].data;
}

void update(int k,int ll,int rr,int c)
{
    if(ll<=ss[k].left&&rr>=ss[k].right)
    {
        ss[k].lazy+=c;
        ss[k].data+=c*(ss[k].right-ss[k].left+1);
        return;
    }
    pushdown(k,ss[k].right-ss[k].left+1);
    int mid=(ss[k].left+ss[k].right)>>1;
    if(ll <= mid)
        update(k<<1,ll,rr,c);
    if(rr > mid)
        update(k<<1|1,ll,rr,c);
    ss[k].data=ss[k<<1].data+ss[k<<1|1].data;
}

long long int  query(int k,int ll,int rr)
{
    if(ll<=ss[k].left&&rr>=ss[k].right)
        return ss[k].data;
    pushdown(k,ss[k].right-ss[k].left+1);

    long long int ans=0;
    int m=(ss[k].left+ss[k].right)>>1;

    if(ll <=m)
        ans+= query(k<<1, ll, rr);
    if(rr >m)
        ans+= query(k<<1|1, ll, rr);
    return ans;
}


int main()
{
    int n,q,op,ed,change;
    long long int   tmp;
    char choice[10];
    //freopen("t","r",stdin);
    scanf("%d%d",&n,&q);
    buildtree(1,1,n);
    while(q--)
    {
        scanf("%s",choice);
        if(choice[0]=='Q') {
            scanf("%d%d",&op,&ed);
            printf("%lld\n",query(1,op,ed));
        }
        else if(choice[0]=='C'){
            scanf("%d%d%d",&op,&ed,&change);
            update(1,op,ed,change);
        }
    }
    return 0;
}
//
//  main.c
//  example
//
//  Created by Adam on 15/2/2.
//  Copyright (c) 2015年 Adam. All rights reserved.
//
// 树状数组成段更新元素
// 首先我们开个数组 ans[i] 表示原序列前i个元素的总和 那么原序列区间[a,b]的总和 ans(a,b) = ans[b]-ans[a];
// sum[i] 表示对序列进行更改后前i个元素的总和
// 我们再开个数组 c1[i]表示 区间[i,n]的每个元素都改变的值
// 例如现在给区间[a,b]每个元素都加上c 只需要对c1这个数组进行更改 c1[a] += c; c1[b+1] -= c;
// sum[a] = ans[a] + c1[1]*a + c1[2]*(a-1) + c1[i]*(a-i+1) + ..... + c1[a]*1;
// sum[a] = ans[a] +   c1[i]*(a-i+1)  (1<=i<=a)
// sum[a] = ans[a] + c1[i]*(a+1)-ci[i]*i (1<=i<=a)
// 那么区间[a,b]的总和 sum(a,b) = sum[b] - sum[a]
//                   sum[a] = ans[a] + c1[i]*(a+1)-ci[i]*i (1<=i<=a)
//                   sum[b] = ans[b] + c1[i]*(b+1)-ci[i]*i (1<=i<=b)
//
//                   sum(a,b) = sum[b] - sum[a]
//                            = ans[b] + c1[i]*(b+1)-ci[i]*i (1<=i<=b) -
//                                ( ans[a] + c1[i]*(a+1)-ci[i]*i (1<=i<=a) )


#include <iostream>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "algorithm"
#include <queue>
#define N 100005
using namespace std;
long long int sum[N];
long long int c1[N];
long long int c2[N];
int n,q;

int lowbit(int x)
{
    return x & (-x);
}

void update(int k, int change, long long int *c)
{
    while(k <= n)
    {
        c[k] += change;
        k += lowbit(k);
    }
}
long long int query(int k, long long int *c)
{
    long long int ans=0;
    while(k)
    {
        ans += c[k];
        k -= lowbit(k);
    }
    return ans;
}
int main()
{
    int a,b,c;
    char choice[2];
    
    scanf("%d %d", &n, &q);
    memset(c1, 0, sizeof c1);
    memset(c2, 0, sizeof c2);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&sum[i]);
        sum[i]+=sum[i-1];
    }
    while(q--)
    {
        scanf("%s", choice);
        if(choice[0] == 'Q'){
            scanf("%d %d", &a, &b);
            printf("%lld\n",sum[b]-sum[a-1]+(b+1)*query(b, c1)-a*query(a-1, c1)-query(b, c2)+query(a-1, c2));
        }
        else{
            scanf("%d %d %d", &a, &b, &c);
            update( a, c, c1);
            update( b+1, -c, c1);
            update( a, c*a, c2);
            update( b+1, -c*(b+1), c2);
            
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值