POJ 3468 A Simple Problem with Integers(分块)

A Simple Problem with Integers

You have N N N integers, A 1 , A 2 , . . . , A N A_1, A_2, ... , A_N A1,A2,...,AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N N N and Q Q Q. 1 ≤ N , Q ≤ 100000 1 ≤ N,Q ≤ 100000 1N,Q100000.
The second line contains N N N numbers, the initial values of A 1 , A 2 , . . . , A N A_1, A_2, ... , A_N A1,A2,...,AN. − 1000000000 ≤ A i ≤ 1000000000. -1000000000 ≤ A_i ≤ 1000000000. 1000000000Ai1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of A a , A a + 1 , . . . , A b A_a, A_{a+1}, ... , A_b Aa,Aa+1,...,Ab. − 10000 ≤ c ≤ 10000. -10000 ≤ c ≤ 10000. 10000c10000.
“Q a b” means querying the sum of A a , A a + 1 , . . . , A b A_a, A_{a+1}, ... , A_b Aa,Aa+1,...,Ab.

Output

You need to answer all Q Q Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

思路

用分块算法,把n分为若干个区间,用"大段维护,局部朴素"的方法来维护全局。

#include<cstdio>
#include<cmath>
#define int long long
using namespace std;
const int maxn=1e5+10;
int sum[maxn],add[maxn],n,m,t,l,r,v;
int a[maxn],L[maxn],R[maxn],pos[maxn];
char op[3];

int ask(int l,int r){
    int p=pos[l],q=pos[r],ret=0;
    if(p==q){
        for(int i=l;i<=r;i++)   ret+=a[i];
        ret+=add[p]*(r-l+1);
    }else{
        ret+=ask(l,R[p]),ret+=ask(L[q],r);
        for(int i=p+1;i<q;i++)  ret+=sum[i]+add[i]*(R[i]-L[i]+1);
    }
    return ret;
}

void change(int l,int r,int v){
    int p=pos[l],q=pos[r];
    if(p==q){
        for(int i=l;i<=r;i++)   a[i]+=v;
        sum[p]+=v*(r-l+1);
    }else{
        change(l,R[p],v),change(L[q],r,v);
        for(int i=p+1;i<q;i++)  add[i]+=v;
    }
}

signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)   scanf("%lld",&a[i]);
    t=sqrt(n);
    for(int i=1;i<=t;i++){
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if(R[t]<n)  t++,L[t]=R[t-1]+1,R[t]=n;
    for(int i=1;i<=t;i++)
        for(int j=L[i];j<=R[i];j++)
            pos[j]=i,sum[i]+=a[j];
    while(m--){
        scanf("%s%lld%lld",op,&l,&r);
        if(op[0]=='Q')  printf("%lld\n",ask(l,r));
        else{
            scanf("%lld",&v);
            change(l,r,v);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值