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;
}