Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 35742 | Accepted: 10240 | |
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
题意:
给出点集数以及命令数;
先将每一个点赋初值
Q a b 表示求出点集中从a到b的和
C a b c 表示将a到b的点全部加c
方法:
线段树,并且单纯的线段树会超时,因为在将a到b的点全部加上c时,步骤太多,会超时。
需要优化。即lazy算法;
Lazy:
在将a~b点全部加c时,不要加到每个点,在表示区间的root结构体上增加一个inc域,将要加的值赋给这个inc域,然后就不要再往下了。
在求区间和时,将root中的inc值赋给要求的区间,并且将该节点的root置零。
第一次做线段树就碰上这个题。。。TLE无数次啊,改了无数次啊。。。
代码实现:
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 struct node{ 5 int r; //root to the left's range 6 int l; 7 node * rt; //the right subtree of the root 8 node * lt; 9 __int64 key; //the root's value 10 __int64 inc; //the root's inc value 11 }; 12 node * buildtree(int left,node * root,int right){ //from root constract a tree 13 root->l=left; 14 root->r=right; 15 root->key=0; 16 root->inc=0; 17 int temp=(left+right)/2; 18 if(left==right){ 19 root->lt=NULL; 20 root->rt=NULL; 21 return root; 22 } 23 node * newleft; 24 newleft=new node; 25 root->lt=newleft; 26 buildtree(left,root->lt,temp); 27 //constract a left-subtree 28 node * newright; 29 newright=new node; 30 root->rt=newright; 31 buildtree(temp+1,root->rt,right); 32 //constract a right-subtree 33 return root; 34 } 35 void insert(int point,node * root1,int real){ //insert a value real to leaf point and change value from leaf to root 36 int temp1=(root1->l+root1->r)/2; 37 if(point==root1->l&&point==root1->r){ 38 root1->key+=real; 39 return ; 40 } 41 root1->key+=real; //from start to end find point, 42 if(point>=root1->l&&point<=temp1){ 43 insert(point,root1->lt,real); 44 } 45 else { 46 insert(point,root1->rt,real); 47 } 48 } 49 void addsum(int left2,int right2,int add,node * root2){ //add a value add to a large of points from left2 to right2 50 if(root2->l==left2&&root2->r==right2){ 51 root2->inc+=add; 52 return ; 53 } 54 root2->key+=add*(right2-left2+1); 55 if(right2<=(root2->l+root2->r)/2){ 56 addsum(left2,right2,add,root2->lt); 57 } 58 else if(left2>=(root2->l+root2->r)/2+1){ 59 addsum(left2,right2,add,root2->rt); 60 } 61 else { 62 addsum(left2,(root2->l+root2->r)/2,add,root2->lt); 63 addsum((root2->l+root2->r)/2+1,right2,add,root2->rt); 64 } 65 } 66 __int64 findsum(int left1,int right1,node * root3){ //find the sum of the points from left1 to right1 67 if(left1==root3->l&&right1==root3->r){ 68 return (root3->key)+(root3->inc*(right1-left1+1)); 69 } 70 root3->key+=root3->inc*(root3->r-root3->l+1); 71 int temp2=(root3->l+root3->r)/2; 72 addsum(root3->l,temp2,root3->inc,root3->lt); 73 addsum(temp2+1,root3->r,root3->inc,root3->rt); 74 root3->inc=0; 75 if(left1>=root3->l&&right1<=temp2){ 76 return findsum(left1,right1,root3->lt); 77 } 78 else if(left1>=temp2+1&&right1<=root3->r){ 79 return findsum(left1,right1,root3->rt); 80 } 81 else { 82 return findsum(left1,(root3->l+root3->r)/2,root3->lt)+findsum((root3->l+root3->r)/2+1,right1,root3->rt); 83 } 84 } 85 int main(){ 86 int n1,n2; 87 while(scanf("%d%d",&n1,&n2)!=EOF){ 88 // getchar(); 89 node * newtree; 90 newtree=new node; 91 buildtree(1,newtree,n1); //consract a tree left to 1 and right to n1 92 for(int g=1;g<=n1;g++){ 93 int tep3; 94 scanf("%d",&tep3); 95 insert(g,newtree,tep3); //insert a leaf g value tep3 96 } 97 for(int i=1;i<=n2;i++){ 98 char temp4; 99 getchar(); 100 scanf("%c",&temp4); 101 if(temp4=='C'){ 102 int temp5,temp6; 103 int temp7; 104 // getchar(); 105 scanf("%d%d%d",&temp5,&temp6,&temp7); 106 addsum(temp5,temp6,temp7,newtree); //add a large of points from temp5 to temp6 value temp7 107 } 108 else if(temp4=='Q'){ 109 // getchar(); 110 int tep1,tep2; 111 scanf("%d%d",&tep1,&tep2); 112 __int64 tep5=findsum(tep1,tep2,newtree); //find the sum of value from tep1 to tep2 113 printf("%I64d\n",tep5); 114 } 115 } 116 // getchar(); 117 } 118 return 0; 119 }