牛客网 2018年全国多校算法寒假训练营练习比赛(第五场) H.Tree Recovery-完全版线段树(区间更新、区间求和)
H.Tree Recovery
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
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.
输入描述:
输出描述:
You need to answer all Q commands in order. One answer in a line.
示例1
输入
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
输出
4 55 9 15
这个题是线段树区间查询求和和区间更新。
代码:
1 /* 2 //H-线段树-区间查询求和和区间更新 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cstdlib> 7 #include<algorithm> 8 using namespace std; 9 typedef long long ll; 10 #define ls l,m,rt<<1 11 #define rs m+1,r,rt<<1|1 12 #define root 1,n,1 13 const int maxn=1e5+10; 14 ll Sum[maxn<<2],Add[maxn<<2];//Sum为求和,Add为懒惰标记 15 ll A[maxn],n;//存原数组数据下标 16 17 //PushUp函数更新节点信息,这里是求和 18 void PushUp(int rt){ 19 Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; 20 } 21 22 //下推标记的函数 23 void PushDown(int rt,int m){ 24 if(Add[rt]){//下推标记 25 Add[rt<<1]+=Add[rt]; 26 Add[rt<<1|1]+=Add[rt]; 27 Sum[rt<<1]+=Add[rt]*(m-(m>>1)); 28 Sum[rt<<1|1]+=Add[rt]*(m>>1); 29 Add[rt]=0;//清除本节点标记 30 } 31 } 32 33 //建树 34 void Build(int l,int r,int rt){//rt表示当前节点编号 35 Add[rt]=0; 36 if(l==r){ 37 Sum[rt]=A[l];return; 38 } 39 int m=(l+r)>>1; 40 Build(ls); 41 Build(rs); 42 PushUp(rt); 43 } 44 45 //区间修改A[L,R]+=C 46 void Update(int L,int R,int C,int l,int r,int rt){ 47 if(L<=l&&r<=R){ 48 Sum[rt]+=(ll)C*(r-l+1); 49 Add[rt]+=C; 50 return ; 51 } 52 PushDown(rt,r-l+1);//下推标记 53 int m=(l+r)>>1; 54 if(L<=m)Update(L,R,C,ls); 55 if(R>m)Update(L,R,C,rs); 56 PushUp(rt);//更新本节点 57 } 58 59 //区间查询A[L,R]的和 60 int Query(int L,int R,int l,int r,int rt){ 61 if(L<=l&&r<=R){ 62 return Sum[rt]; 63 } 64 PushDown(rt,r-l+1);//下推标记,否则Sum可能不正确 65 int m=(l+r)>>1; 66 ll ANS=0;//累计答案 67 if(L<=m)ANS+=Query(L,R,ls); 68 if(R>m)ANS+=Query(L,R,rs); 69 return ANS; 70 } 71 72 int main(){ 73 int n,m; 74 scanf("%d%d",&n,&m); 75 for(int i=1;i<=n;i++) 76 scanf("%lld",&A[i]); 77 Build(1,n,1);//建树 78 while(m--){ 79 char str[2]; 80 scanf("%s",str); 81 if(str[0]=='Q'){ 82 int a,b; 83 scanf("%d%d",&a,&b); 84 ll ANS=Query(a,b,root);//区间查询 85 printf("%lld\n",ANS); 86 } 87 else{ 88 int a,b,C; 89 scanf("%d%d%d",&a,&b,&C); 90 Update(a,b,C,root);//区间修改 91 } 92 } 93 return 0; 94 } 95 */ 96 /* 97 样例 98 10 5 99 1 2 3 4 5 6 7 8 9 10 100 Q 4 4 101 Q 1 10 102 Q 2 4 103 C 3 6 3 104 Q 2 4 105 */
就这样,还有二维线段树,还没写,以后写。
滚去看搜索了,简直被虐爆了,难受。