Description
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 abc" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q ab" 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
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 #define N 210000 7 8 struct node 9 { 10 long long l, r, sum, op, e; // op 代表是否更新,e代表要更新的数是多少 11 int len(){return (r-l+1);} // 区间长度 12 }tree[N*4]; 13 14 long long cnt[N]; 15 16 void Build(int root, int l, int r) 17 { 18 tree[root].l = l; 19 tree[root].r = r; 20 tree[root].op = -1; // 初始化全部不需要更新 21 tree[root].e = 0; // 需要加的值为0 22 23 if(tree[root].l == tree[root].r) 24 { 25 tree[root].sum = cnt[l]; // 到叶子节点时总和就是自身 26 return ; 27 } 28 Build(2*root, l, (l+r)/2); 29 Build(2*root+1, (l+r)/2+1, r); 30 tree[root].sum = tree[root*2].sum + tree[root*2+1].sum; // 这棵树上的和等于左儿子和右儿子的总和 31 } 32 33 void Down(int root) // 向下更新 34 { 35 if(tree[root].op && tree[root].l != tree[root].r) 36 { 37 tree[root].op = false; 38 39 tree[root*2].op = tree[root*2+1].op = true; 40 tree[root*2].e += tree[root].e; 41 tree[root*2+1].e += tree[root].e; 42 43 tree[root*2].sum += tree[root].e*tree[root*2].len(); 44 tree[root*2+1].sum += tree[root].e*tree[root*2+1].len(); 45 46 tree[root].e = 0; 47 48 } 49 } 50 51 void update(int root, int a, int b, int e) 52 { 53 Down(root); // 每次都可能会向下更新 54 55 tree[root].sum += (b-a+1)*e; // 这棵树上要家的值是a~b的长度乘以每一个数要加的e,因为这棵树上肯定包括这个区间(否则不会到这棵树上,所以这棵树上的总和要加上 56 57 if(tree[root].l == a && tree[root].r == b) // 如果这颗树上所有的数都要加数,更新,那么就把这颗树上的op置为1,意味着下边的树要更新,要向下Down,同时就不要向下update了,直接return就行 58 { 59 tree[root].e = e; // 这棵树上要更新的值为e 60 tree[root].op = true; 61 return ; 62 } 63 int mid = (tree[root].l+tree[root].r)/2; 64 65 if(b <= mid) 66 update(2*root, a, b, e); 67 else if(a > mid) 68 update(2*root+1, a, b, e); 69 else 70 { 71 update(2*root, a, mid, e); 72 update(2*root+1, mid+1, b, e); 73 } 74 75 tree[root].sum = tree[root*2].sum + tree[root*2+1].sum; // 树上总和等于两个儿子总和 76 } 77 78 long long query(int root, int l, int r) // 计算l~r的和 79 { 80 if(tree[root].l == l && tree[root].r == r)
82 return tree[root].sum;
84 85 Down(root); //如果需要也要向下更新 86 87 int mid = (tree[root].l+tree[root].r)/2; 88 89 if(r <= mid) 90 return query(2*root, l, r); 91 else if(l > mid) 92 return query(2*root+1, l, r); 93 return query(root*2, l, mid)+query(root*2+1, mid+1, r); 94 } 95 int main() 96 { 97 long long n, q, a, b, c; 98 char s[9]; 99 100 while(scanf("%lld%lld", &n, &q) != EOF) 101 { 102 for(int i = 1; i <= n; i++) 103 scanf("%lld", &cnt[i]); 104 105 Build(1, 1, n); 106 107 while(q--) 108 { 109 scanf("%s", s); 110 111 if(s[0] == 'Q') 112 { 113 scanf("%lld%lld", &a, &b); 114 printf("%lld ", query(1, a, b)); 115 } 116 else if(s[0] =='C') 117 { 118 scanf("%lld%lld%lld", &a, &b, &c); 119 update(1, a, b, c); 120 } 121 } 122 } 123 return 0; 124 }
也可以这么做:www.cnblogs.com/alihenaixiao/p/4611575.html
解题思路:
线段树更新到每一个节点的话,由于节点数目和查询次数原因会tle,所以在每一个节点内定义一个标志变量表示当前节点的下一层为更新,每次查询时候有需要的话在更新到下一层。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 400010; 7 const int INF = 0x3f3f3f3f; 8 #define LL __int64 9 struct node 10 { 11 LL L, R; 12 LL sum, add; 13 LL Mid() 14 { 15 return (L + R) / 2; 16 } 17 }; 18 node tree[maxn]; 19 LL res; 20 21 void build(LL root, LL l, LL r) 22 { 23 tree[root].L = l; 24 tree[root].R = r; 25 tree[root].sum = tree[root].add = 0; 26 27 if (l == r) 28 return ; 29 build (2*root+1, l, tree[root].Mid()); 30 build (2*root+2, tree[root].Mid()+1, r); 31 } 32 void insert (LL root, LL s, LL e, LL x) 33 { 34 tree[root].sum += x * (e - s + 1); 35 if (tree[root].L == s && e == tree[root].R)//更新到区间 36 { 37 tree[root].add += x; 38 return ; 39 } 40 if (e <= tree[root].Mid()) 41 insert (2*root+1, s, e, x); 42 else if (tree[root].Mid() < s) 43 insert (2*root+2, s, e, x); 44 else 45 { 46 insert (2*root+1, s, tree[root].Mid(), x); 47 insert (2*root+2, tree[root].Mid()+1, e, x); 48 } 49 } 50 void query (LL root, LL s, LL e) 51 { 52 53 if (tree[root].L == s && e == tree[root].R) 54 { 55 res += tree[root].sum; 56 return ; 57 } 58 if (tree[root].add) 59 {//向下继续更新 60 tree[2*root+1].add += tree[root].add; 61 tree[2*root+2].add += tree[root].add; 62 tree[2*root+1].sum += tree[root].add * (tree[2*root+1].R - tree[2*root+1].L + 1); 63 tree[2*root+2].sum += tree[root].add * (tree[2*root+2].R - tree[2*root+2].L + 1); 64 tree[root].add = 0; 65 } 66 if (e <= tree[root].Mid()) 67 query (2*root+1, s, e); 68 else if (tree[root].Mid() < s) 69 query (2*root+2, s, e); 70 else 71 { 72 query (2*root+1, s, tree[root].Mid()); 73 query (2*root+2, tree[root].Mid()+1, e); 74 } 75 } 76 int main () 77 { 78 LL n, m, num; 79 while (scanf ("%I64d %I64d", &n, &m) != EOF) 80 { 81 build (0, 1, n); 82 for (int i=1; i<=n; i++) 83 { 84 scanf ("%I64d", &num); 85 insert (0, i, i, num); 86 } 87 char str[2]; 88 LL s, e; 89 while (m --) 90 { 91 scanf ("%s %I64d %I64d", str, &s, &e); 92 if (str[0] == 'Q') 93 { 94 res = 0; 95 query (0, s, e); 96 printf ("%I64d ", res); 97 } 98 else 99 { 100 scanf ("%I64d", &num); 101 insert (0, s, e, num); 102 } 103 } 104 } 105 return 0; 106 }