略,见以前的blog区间操作 Splay。今天用线段树写一下。
写这个是为了写【USACO 2011 December Gold】Grass Planting种草 做准备(好久没写树链剖分了qaq)
解题思路
维护一个属性Sum,一个标记Add
下传标记时儿子的Sum也要加Add*儿子的范围内的个数。
还有就是下传了标记要把标记清零(我居然把这个都忘了)。
代码
#include <bits/stdc++.h>
#define Maxn 100005
using namespace std;
inline char Getch(){
char ch=getchar();
while(ch!='Q'&&ch!='C')ch=getchar();
return ch;
}
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int vl[Maxn];
struct node{
long long L,r,Sum,Add;
}Tree[400005];
void Build(int v,int L,int r){
Tree[v]=(node){L,r,0,0};
if(L==r)return;
Build(2*v,L,(L+r)/2);
Build(2*v+1,(L+r)/2+1,r);
}
void PushDown(int v){
Tree[2*v].Add+=Tree[v].Add;
Tree[2*v+1].Add+=Tree[v].Add;
Tree[2*v].Sum+=Tree[v].Add*(Tree[2*v].r-Tree[2*v].L+1);
Tree[2*v+1].Sum+=Tree[v].Add*(Tree[2*v+1].r-Tree[2*v+1].L+1);
Tree[v].Add=0;
}
void PushUp(int v){
Tree[v].Sum=Tree[2*v].Sum+Tree[2*v+1].Sum;
}
long long Ask(int v,int L,int r){
if(r<Tree[v].L||Tree[v].r<L)return 0;
if(L<=Tree[v].L&&Tree[v].r<=r)return Tree[v].Sum;
PushDown(v);
return Ask(2*v,L,r)+Ask(2*v+1,L,r);
}
void Modify(int v,int L,int r,int c){
if(r<Tree[v].L||Tree[v].r<L)return;
if(L<=Tree[v].L&&Tree[v].r<=r){
Tree[v].Sum+=c*(Tree[v].r-Tree[v].L+1);
Tree[v].Add+=c;
return;
}
PushDown(v);
Modify(2*v,L,r,c);
Modify(2*v+1,L,r,c);
PushUp(v);
}
int main(){
int n=Getint(),q=Getint();
for(int i=1;i<=n;i++)vl[i]=Getint();
Build(1,1,n);
for(int i=1;i<=n;i++)Modify(1,i,i,vl[i]);
while(q--){
if(Getch()=='Q'){
int L=Getint(),r=Getint();
cout<<Ask(1,L,r)<<"\n";
}else{
int L=Getint(),r=Getint(),c=Getint();
Modify(1,L,r,c);
}
}
return 0;
}