线段树优化 lazy算法 poj3468

A Simple Problem with Integers
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无数次啊,改了无数次啊。。。

 

 

代码实现:

 

View Code
  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 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值