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 a b 。表示查询从a到b的所有数的和,第二种:C a b c 。表示把从a到b的所有数都加上c包括a和b。你需要按顺序给出所有查询的语句。
输入:第一行n ,q,来表示有n个数,q表示有多少个语句1<=n,q<=100000.第二行为n个数的初始数值:A1,A2,A3,,,,An,-100000000<=Ai<=100000000.接下来是q个查询语句。注意结果的总和可能超过32为整数
思路:线段树的模板,用到了区间加和,懒惰标记,和区间求和,比较注意的 是数比较大,所以我用的是longlong,
代码:
1 #include <cstdio> 2 #include <fstream> 3 #include <algorithm> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <string> 9 #include <cstring> 10 #include <map> 11 #include <stack> 12 #include <set> 13 #include <sstream> 14 #include <iostream> 15 #define mod 998244353 16 #define eps 1e-6 17 #define ll long long 18 #define INF 0x3f3f3f3f 19 using namespace std; 20 21 struct node 22 { 23 //l表示左边,r表示右边,sum表示该线段的值 24 ll l,r,sum; 25 ll lazy; 26 }; 27 node no[600000]; 28 //存放每个点的值 29 ll number[100000]; 30 31 inline void update(int k) 32 { 33 //用左右线段的值更新该线段的值 34 no[k].sum=no[k*2].sum+no[k*2+1].sum; 35 } 36 //初始化 37 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界 38 void build(ll k,ll l,ll r) 39 { 40 no[k].lazy=0; 41 no[k].l=l; 42 no[k].r=r; 43 //如果递归到最低点 44 if(l==r) 45 { 46 //赋值并记录该点对应的节点编号 47 no[k].sum=number[l]; 48 return ; 49 } 50 //对半分 51 ll mid=(l+r)/2; 52 //递归到左线段 53 build(k*2,l,mid); 54 //递归到右线段 55 build(k*2+1,mid+1,r); 56 update(k); 57 } 58 void pushdown(ll k) 59 { 60 //如果节点k已经是叶节点了,没有子节点,那么标记就不用下传,直接删除就可以了 61 if(no[k].l==no[k].r) 62 { 63 no[k].lazy=0; 64 return ; 65 } 66 //给k的子节点重新赋值 67 no[k*2].sum+=(no[k*2].r-no[k].l+1)*no[k].lazy; 68 no[k*2+1].sum+=(no[k*2+1].r-no[k*2+1].l+1)*no[k].lazy; 69 //下传点k的标记 70 no[k*2].lazy+=no[k].lazy; 71 no[k*2+1].lazy+=no[k].lazy; 72 //清空点k的标记 73 no[k].lazy=0; 74 } 75 76 void change(ll k,ll l,ll r,ll x) 77 { 78 //如果当前节点被打上了懒惰标记,那么就把这个标记下传, 79 if(no[k].lazy) 80 { 81 pushdown(k); 82 } 83 84 if(no[k].l==l&&no[k].r==r) 85 { 86 no[k].sum+=(r-l+1)*x; 87 no[k].lazy+=x; 88 return ; 89 } 90 91 ll mid = (no[k].l+no[k].r)/2; 92 if(r<=mid) 93 { 94 change(k*2,l,r,x); 95 } 96 else if(l>mid) 97 { 98 change(k*2+1,l,r,x); 99 } 100 else 101 { 102 change(k*2,l,mid,x); 103 change(k*2+1,mid+1,r,x); 104 } 105 update(k); 106 } 107 108 //查询指定区间内的所有的和 109 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界 110 ll query(ll k,ll l,ll r) 111 { 112 //如果当前区间就是询问区间,完全重合,那么显然可以直接返回 113 if(no[k].l==l&&no[k].r==r) 114 { 115 return no[k].sum; 116 } 117 //如果当前节点被打上了懒惰标记,那么就把这个标记下传, 118 if(no[k].lazy) 119 { 120 pushdown(k); 121 } 122 //取中值 123 ll mid = (no[k].l+no[k].r)/2; 124 //如果询问区间包含在左子区间中 125 if(r<=mid) 126 { 127 return query(k*2,l,r); 128 } 129 else if(l>mid)//如果询问区间包含在右子区间中 130 { 131 return query(k*2+1,l,r); 132 } 133 else//如果询问区间跨越两个子区间 134 { 135 return query(k*2,l,mid)+query(k*2+1,mid+1,r); 136 } 137 } 138 139 int main() 140 { 141 ll m,n; 142 scanf("%I64d %I64d",&m,&n); 143 for(ll i=1;i<=m;i++) 144 { 145 scanf("%I64d",&number[i]); 146 } 147 build(1,1,m); 148 char str[2]; 149 ll a,b,c; 150 while(n--) 151 { 152 cin>>str; 153 if(str[0]=='Q') 154 { 155 scanf("%I64d %I64d",&a,&b); 156 printf("%I64d ",query(1,a,b)); 157 } 158 else if(str[0]=='C') 159 { 160 scanf("%I64d %I64d %I64d",&a,&b,&c); 161 change(1,a,b,c); 162 } 163 } 164 }