魔法树
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; }