Description
给出了一个序列,你需要处理如下两种询问。
"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。
"Q a b" 询问[a, b]区间中所有值的和。
Input
第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.
第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。
接下来Q行询问,格式如题目描述。
Output
对于每一个Q开头的询问,你需要输出相应的答案,每个答案一行。
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<cstdio> 2 #include<cstring> 3 #include<iostream> 4 5 using namespace std; 6 7 const int MAXN=500000; 8 9 struct student 10 { 11 int left,right; 12 __int64 nSum; 13 __int64 Mark; 14 }segTree[MAXN*4]; 15 __int64 num[MAXN]; //__int64是Windows专用的专门用于记录超大数据的类型,防止越界 16 17 18 19 void Build(int index,int l,int r) //建树 20 { 21 segTree[index].left=l; 22 segTree[index].right=r; 23 if(segTree[index].left==segTree[index].right) 24 { 25 segTree[index].nSum=num[l-1]; 26 return ; 27 } 28 int mid=(l+r)/2; 29 Build(2*index,l,mid); 30 Build(2*index+1,mid+1,r); 31 segTree[index].nSum=segTree[index*2].nSum+segTree[index*2+1].nSum; //每个节点和 32 } 33 34 35 36 37 38 void Add(int i,int left,int right,int b) 39 { 40 if(segTree[i].left>=left&&segTree[i].right<=right) 41 { 42 segTree[i].nSum+=(segTree[i].right-segTree[i].left+1)*b;//倍数加 43 segTree[i].Mark+=b;//用+=原因是某段可能会被多次标记 44 return ; 45 } 46 else 47 { 48 if(segTree[i].Mark) //最关键部分就是这个标记下传,将增加值val传给他的左右孩子 49 { 50 segTree[i*2].nSum+=segTree[i].Mark*(segTree[i*2].right-segTree[i*2].left+1); 51 segTree[i*2].Mark+=segTree[i].Mark; 52 segTree[i*2+1].nSum+=segTree[i].Mark*(segTree[i*2+1].right-segTree[i*2+1].left+1); 53 segTree[i*2+1].Mark+=segTree[i].Mark; 54 segTree[i].Mark=0; 55 } 56 if(right>=segTree[i*2+1].left) 57 Add(2*i+1,left,right,b); 58 if(left<=segTree[i*2].right) 59 Add(2*i,left,right,b); 60 61 segTree[i].nSum=segTree[i*2].nSum+segTree[i*2+1].nSum; 62 } 63 64 65 } 66 67 68 69 __int64 Query(int i,int left,int right) 70 { 71 if(segTree[i].left>=left&&segTree[i].right<=right) 72 return segTree[i].nSum; 73 if(segTree[i].Mark) //求和同样需要标记下传 74 { 75 segTree[i*2].nSum+=segTree[i].Mark*(segTree[i*2].right-segTree[i*2].left+1); 76 segTree[i*2].Mark+=segTree[i].Mark; 77 segTree[i*2+1].nSum+=segTree[i].Mark*(segTree[i*2+1].right-segTree[i*2+1].left+1); 78 segTree[i*2+1].Mark+=segTree[i].Mark; 79 segTree[i].Mark=0; 80 } 81 int mid=(segTree[i].left+segTree[i].right)/2; 82 __int64 max1=0,max2=0; 83 if(mid<left) 84 max1= Query(2*i+1,left,right); 85 else 86 if(right<=mid) 87 max1=Query(2*i,left,right); 88 else 89 { 90 max1=Query(2*i,left,mid); 91 max2=Query(2*i+1,mid+1,right); 92 } 93 return max1+max2; 94 95 96 97 } 98 99 100 101 102 103 int main() 104 { 105 int n,t; 106 int x,y,z; 107 108 char C; 109 while(scanf("%d%d",&n,&t)!=EOF) 110 { 111 memset(segTree,0,sizeof(segTree)); 112 for(int i=0; i<n; i++) 113 scanf("%I64d",&num[i]); 114 Build(1,1,n); 115 for (int j=0;j<t;j++) 116 { 117 getchar(); 118 scanf("%c%d%d",&C,&x,&y); 119 120 if(C == ‘C‘) 121 { 122 scanf("%d",&z); 123 Add(1,x,y,z); 124 } 125 else 126 printf("%I64d\n",Query(1,x,y)); 127 } 128 129 } 130 return 0; 131 }
时间: 2024-10-21 01:24:18