BZOJ 3212: Pku3468 A Simple Problem with Integers【树状数组||线段树】

3212: Pku3468 A Simple Problem with Integers

Time Limit: 1 Sec Memory Limit: 128 MB

Description

You have N integers, 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 and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.

Output

You need to answer all 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

HINT

The sums may exceed the range of 32-bit integers.

题目大意

给你一个长度为N序列,然后Q次命令。若开头字母为Q,表示询问L到R之间数字和;若开头字母为C,在L到R之间每个增加C。

题解

这题是裸的线段树,不用说吧,线段树+PushDown,但是我想讲一种新的方法,树状数组这个神奇的想法。
我们想只要我们像容斥一样,在L的位置+C,在R+1的位置-C,就能做到区间修改。
额其实我也不是很懂,只是听老师讲过,但是忘了,只有代码还有,如果有大神会,跪求题解。

树状数组代码

#include<cstdio>
#include<cctype>
#define LL long long
using namespace std;
int n,q;
LL c[2][100005];
int read(){
    int ret=0;bool f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-'0';
    return f?ret:-ret;
}
void Add(int x,LL t){for(int i=x;i<=n;i+=i&-i) c[0][i]+=t,c[1][i]+=t*x;}
LL get(int x){
    LL sum=0;
    for(int i=x;i;i-=i&-i) sum+=((LL)x+1)*c[0][i]-c[1][i];
    return sum;
}
int main(){
//  freopen("prob.in","r",stdin);
//  freopen("prob.out","w",stdout);
    n=read(),q=read();
    for(int i=1;i<=n;i++){
        int x=read();
        Add(i,x);Add(i+1,-x);
    }
    for(int i=1;i<=q;i++){
        int L,R,x;char ch[10];scanf("%s",ch);
        if(ch[0]=='C') L=read(),R=read(),x=read(),Add(L,x),Add(R+1,-x);
        else L=read(),R=read(),printf("%lld\n",get(R)-get(L-1));
    }
    return 0;
}

线段树代码

#include<cstdio>
#define MAXN 100005
#define LL long long
using namespace std;
int a[MAXN],n,q;LL Tre[MAXN<<2],Add[MAXN<<2];
void Build(int l,int r,int x){
    if(l==r){Tre[x]=a[l];return;}
    int mid=(r+l)>>1;
    Build(l,mid,x<<1);Build(mid+1,r,x<<1|1);
    Tre[x]+=Tre[x<<1]+Tre[x<<1|1];
}
void PushDown(int x,int Ln,int Rn){
    if(Add[x]){
        Add[x<<1]+=Add[x];
        Add[x<<1|1]+=Add[x];
        Tre[x<<1]+=Add[x]*Ln;
        Tre[x<<1|1]+=Add[x]*Rn;
        Add[x]=0;
    }
}
void Updata(int L,int R,int l,int r,int C,int x){
    if(L<=l&&r<=R){Tre[x]+=C*(r-l+1),Add[x]+=C;return;}
    int mid=(r+l)>>1;
    PushDown(x,mid-l+1,r-mid);
    if(L<=mid) Updata(L,R,l,mid,C,x<<1);
    if(mid<R) Updata(L,R,mid+1,r,C,x<<1|1);
    Tre[x]=Tre[x<<1]+Tre[x<<1|1];
}
LL Query(int L,int R,int l,int r,int x){
    if(L<=l&&r<=R) return Tre[x];
    int mid=(l+r)>>1;
    PushDown(x,mid-l+1,r-mid);
    LL Sum=0;
    if(L<=mid) Sum+=Query(L,R,l,mid,x<<1);
    if(mid<R) Sum+=Query(L,R,mid+1,r,x<<1|1);
    return Sum;
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    Build(1,n,1);
    for(int i=1;i<=q;i++){
        int L,R,x;char ch[10];
        scanf("%s",ch);
        if(ch[0]=='Q') scanf("%d%d",&L,&R),printf("%lld\n",Query(L,R,1,n,1));
        else scanf("%d%d%d",&L,&R,&x),Updata(L,R,1,n,x,1);
    }
    return 0;
}
posted @ 2018-04-19 08:50  XSamsara  阅读(94)  评论(0编辑  收藏  举报