线段树区间求和树节点不能只存和,只存和,会导致每次加数的时候都要更新到叶子节点,速度太慢(O(nlogn))。所以我们要存两个量,一个是原来的和nSum,一个是累加的增量Inc。
在增加时,如果要加的区间正好覆盖一个节点,则增加其节点的Inc值,不再往下走,否则要更新nSum(加上本次增量),再将增量往下传,这样更新的复杂度就是O(log(n))。
在查询时,如果待查区间不是正好覆盖一个节点,就将节点的Inc往下带,然后将Inc清0,接下来再往下查询。 Inc往下带的过程也是区间分解的过程,复杂度也是O(log(n))。
A Simple Problem with Integers
Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 79334 | Accepted: 24455 | |
Case Time Limit: 2000MS |
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 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
1 #include <iostream> 2 #include<cstdio> 3 using namespace std; 4 struct CNode 5 { 6 int L ,R; 7 CNode * pLeft, * pRight; 8 long long nSum; //原来的和 9 long long Inc; //增量c的累加 10 }; 11 CNode Tree[200010]; // 2倍叶子节点数目就够 12 int nCount = 0; 13 int Mid( CNode * pRoot) 14 { 15 return (pRoot->L + pRoot->R)/2; 16 } 17 void BuildTree(CNode * pRoot,int L, int R) 18 { 19 pRoot->L = L; 20 pRoot->R = R; 21 pRoot->nSum = 0; 22 pRoot->Inc = 0; 23 if( L == R) 24 return; 25 nCount ++; 26 pRoot->pLeft = Tree + nCount; 27 nCount ++; 28 pRoot->pRight = Tree + nCount; 29 BuildTree(pRoot->pLeft,L,(L+R)/2); 30 BuildTree(pRoot->pRight,(L+R)/2+1,R); 31 } 32 void Insert( CNode * pRoot,int i, int v) 33 { 34 if( pRoot->L == i && pRoot->R == i) 35 { 36 pRoot->nSum = v; 37 return ; 38 } 39 pRoot->nSum += v; 40 if( i <= Mid(pRoot)) 41 Insert(pRoot->pLeft,i,v); 42 else 43 Insert(pRoot->pRight,i,v); 44 } 45 void Add( CNode * pRoot, int a, int b, long long c) 46 { 47 if( pRoot->L == a && pRoot->R == b) 48 { 49 pRoot->Inc += c; 50 return ; 51 } 52 pRoot->nSum += c * ( b - a + 1) ; 53 if( b <= (pRoot->L + pRoot->R)/2) 54 Add(pRoot->pLeft,a,b,c); 55 else if( a >= (pRoot->L + pRoot->R)/2 +1) 56 Add(pRoot->pRight,a,b,c); 57 else 58 { 59 Add(pRoot->pLeft,a, 60 (pRoot->L + pRoot->R)/2 ,c); 61 Add(pRoot->pRight, 62 (pRoot->L + pRoot->R)/2 + 1,b,c); 63 } 64 } 65 long long QuerynSum( CNode * pRoot, int a, int b) 66 { 67 if( pRoot->L == a && pRoot->R == b) 68 return pRoot->nSum + 69 (pRoot->R - pRoot->L + 1) * pRoot->Inc ; 70 pRoot->nSum += (pRoot->R - pRoot->L + 1) * pRoot->Inc ; 71 Add( pRoot->pLeft,pRoot->L,Mid(pRoot),pRoot->Inc); 72 Add( pRoot->pRight,Mid(pRoot) + 1,pRoot->R,pRoot->Inc); 73 pRoot->Inc = 0; 74 if( b <= Mid(pRoot)) 75 return QuerynSum(pRoot->pLeft,a,b); 76 else if( a >= Mid(pRoot) + 1) 77 return QuerynSum(pRoot->pRight,a,b); 78 else 79 { 80 return QuerynSum(pRoot->pLeft,a,Mid(pRoot)) + 81 QuerynSum(pRoot->pRight,Mid(pRoot) + 1,b); 82 } 83 } 84 int main() 85 { 86 int n,q,a,b,c; 87 char cmd[10]; 88 scanf("%d%d",&n,&q); 89 int i,j,k; 90 nCount = 0; 91 BuildTree(Tree,1,n); 92 for( i = 1; i <= n; i ++ ) 93 { 94 scanf("%d",&a); 95 Insert(Tree,i,a); 96 } 97 for( i = 0; i < q; i ++ ) 98 { 99 scanf("%s",cmd); 100 if ( cmd[0] == ‘C‘ ) 101 { 102 scanf("%d%d%d",&a,&b,&c); 103 Add( Tree,a,b,c); 104 } 105 else 106 { 107 scanf("%d%d",&a,&b); 108 printf("%I64d\n",QuerynSum(Tree,a,b)); 109 } 110 } 111 return 0; 112 }