Description
人类和精灵的联络被巫妖王破坏了,巫妖王决定消灭精灵族以绝后患。 拉席克:“亡灵正在攻过来!” 法里奥:“看来只有暂时抵挡了。” 作为精灵的先知,法里奥召唤出了一排树木,挡住了亡灵的进攻,可是亡灵改变战略,集中攻击一段树木,法里奥为了加强防御不 得不施魔法将这一段树加高。
对于亡灵的每一次进攻,法里奥需要知道进攻区间的防御力, 定义区间的防御力为这一段区间所有树的高度和。
法里奥还在忙着施法,所以需要你来帮他完成这个任务
Input
第一行,两个数 N,M,表示树的数量和操作数,数的编号为0到N−1。
第二行 N 个数,表示树的初始高度。
接下来 M 行,每行一个操作:
C l r h 表示法里奥施法将 l 到 r 的树加高了 ℎ
Q l r 表示亡灵攻击了 l 到 r,法里奥向你询问 l 到 r 之间树的高度和。
Output
对于每一个 Q 操作,输出一个结果。
Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 3 3
Q 0 9
Q 1 3
C 2 5 3
Q 1 3
Sample Output
4
55
9
15
Hint
N≤1000000,M≤5000 初始高度不超过 100
【分析】
这道题的M其实很小,那么我们只需要记下每次操作,然后每次询问暴力扫一遍即可。
但是我用这道题来演示一下堆式线段树(也叫完全二叉线段树)。
【代码】
/*
若当前这段的编号为id。
则在堆式线段树中,其左儿子编号为id*2,右儿子编号为id*2+1
(跟堆的记法一样)
这样可以压常数,有些时候很有用。
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int L,R;
long long sum,lazy;
}Tree[4000005];
int N,M,h[1000005];;
char t[100];
void _in(int &x)
{
char t=getchar();
while(t<'0'||'9'<t) t=getchar();
for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());
}
void _out(long long x,int j=1)
{
if(x==0)printf("0");
for(;x;x/=10,j++) t[j]=x%10+'0';
for(j--;j;j--)putchar(t[j]);
putchar('\n');
}
void _putdown(int id)
{
Tree[(id<<1)].lazy+=Tree[id].lazy;
Tree[(id<<1)+1].lazy+=Tree[id].lazy;
Tree[(id<<1)].sum+=Tree[id].lazy*((long long)(Tree[(id<<1)].R+1-Tree[(id<<1)].L));
Tree[(id<<1)+1].sum+=Tree[id].lazy*((long long)(Tree[(id<<1)+1].R+1-Tree[(id<<1)+1].L));
Tree[id].lazy=0;
}
void _built(int id,int l,int r)
{
Tree[id].L=l;Tree[id].R=r;
if(l==r)
{
Tree[id].sum=h[l];
return;
}
int mid=(l+r)>>1;
_built((id<<1),l,mid);
_built((id<<1)+1,mid+1,r);
Tree[id].sum=Tree[(id<<1)].sum+Tree[(id<<1)+1].sum;
}
void _insert(int id,int l,int r,int v)
{
if(Tree[id].lazy!=0&&Tree[id].R!=Tree[id].L)
_putdown(id);
if(l<=Tree[id].L&&Tree[id].R<=r)
{
Tree[id].lazy+=v;
Tree[id].sum+=((long long)(v))*((long long)(Tree[id].R+1-Tree[id].L));
return;
}
if(!(r<Tree[(id<<1)].L||Tree[(id<<1)].R<l)) _insert((id<<1),l,r,v);
if(!(r<Tree[(id<<1)+1].L||Tree[(id<<1)+1].R<l)) _insert((id<<1)+1,l,r,v);
Tree[id].sum=Tree[(id<<1)].sum+Tree[(id<<1)+1].sum;
}
long long _findans(int id,int l,int r)
{
if(Tree[id].lazy!=0&&Tree[id].L!=Tree[id].R)
_putdown(id);
if(l<=Tree[id].L&&Tree[id].R<=r)
return Tree[id].sum;
long long temp=0;
if(!(r<Tree[(id<<1)].L||Tree[(id<<1)].R<l))
temp+=_findans((id<<1),l,r);
if(!(r<Tree[(id<<1)+1].L||Tree[(id<<1)+1].R<l))
temp+=_findans((id<<1)+1,l,r);
return temp;
}
void _init()
{
_in(N);_in(M);
for(int i=1;i<=N;i++)
_in(h[i]);
_built(1,1,N);
}
void _solve()
{
string s;
int x,y,z;
for(int i=1;i<=M;i++)
{
cin>>s;
_in(x);_in(y);
x++;y++;
if(s[0]=='C')
{
_in(z);
_insert(1,x,y,z);
}
else
_out(_findans(1,x,y));
}
}
int main()
{
_init();
_solve();
return 0;
}