• 线段树的lazy(poj3468)


    A Simple Problem with Integers
    Time Limit: 5000MS   Memory Limit: 131072K
    Total Submissions: 73163   Accepted: 22585
    Case Time Limit: 2000MS

    Description

    You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of AaAa+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

    The sums may exceed the range of 32-bit integers.

    Source

     
      最裸的线段树lazy标记
     
     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 const int N = 100005;
     5 typedef  long long LL;
     6 LL sum[N<<2]; //sum用来存储每个节点的子节点数值的总和
     7 LL add[N<<2];//add用来记录该节点的每个数值应该加多少
     8 struct Node{
     9     int l,r;//表示改点的左右区间 
    10     int mid(){//结构体函数 
    11         return (l+r)>>1;
    12     }
    13 } tree[N<<2];
    14 
    15 void PushUp(int rt){//算某一节点的左右孩子值的和 
    16     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    17 }
    18 
    19 void PushDown(int rt,int m){//rt当前节点  m此节点的区间长度 
    20     if(add[rt]!=0){//如果当前节点lazy标记不为 0 
    21         add[rt<<1] += add[rt];//左右孩子lazy累加 
    22         add[rt<<1|1] += add[rt];
    23         sum[rt<<1] += add[rt]*(m-(m>>1));//更新计算左右孩子 
    24         sum[rt<<1|1] += add[rt] * (m>>1);
    25         add[rt] = 0;//小细节,但很重要,不能忘记lazy用过后清零 
    26     }
    27 }
    28 
    29 void build(int l,int r,int rt){
    30     tree[rt].l = l;
    31     tree[rt].r = r;
    32     add[rt] = 0;//lazy标记记为0 
    33     if(l == r){
    34         scanf("%lld",&sum[rt]);//把子节点信息记录在sum里 
    35         return ;
    36     }
    37     int m = tree[rt].mid();
    38     build(l,m,rt<<1);//建立左右孩子,这时编号是按照类似“宽搜”来编的 
    39     build(m+1,r,rt<<1|1);
    40     
    41     PushUp(rt);//算出此节点的权值 
    42 }
    43 
    44 void update(int c,int l,int r,int rt){//当前节点rt,在l和r区间上加上c  
    45     if(l<=tree[rt].l&&tree[rt].r<=r){//当前节点所表示的区间完全被所要更新的区间包含 
    46         add[rt]+=c;//lazy累加,add[i]数组是针对i左右孩子的 
    47         sum[rt]+=(LL)c*(tree[rt].r-tree[rt].l+1);//这句话很重要和下面的PushUP()类似 
    48         return;
    49     }
    50     PushDown(rt,tree[rt].r - tree[rt].l + 1);//用rt的lazy更新其子节点 
    51     int m = tree[rt].mid();
    52     if(l<=m) update(c,l,r,rt<<1);
    53     if(m+1<=r) update(c,l,r,rt<<1|1);
    54     PushUp(rt);
    55 }
    56 
    57 LL query(int l,int r,int rt){//当前节点为rt,求l,到r的和 
    58     if(l<=tree[rt].l&&tree[rt].r<=r){//区间完全包含,可以直接返回 
    59         return sum[rt];
    60     }
    61     //因为此时用到rt节点,所以才更新lazy 
    62     PushDown(rt,tree[rt].r-tree[rt].l + 1);
    63     
    64     int m = tree[rt].mid();
    65     LL res = 0;
    66     
    67     if(l<= m)//要求的区间有一部分在mid的左边 
    68         res += query(l,r,rt<<1);
    69     if(m+1<=r) 
    70         res += query(l,r,rt<<1|1);
    71     return res;
    72 }
    73 
    74 int main(){
    75 
    76     int n,m;
    77     
    78     scanf("%d %d",&n,&m); 
    79     build(1,n,1);
    80        
    81     while(m--){
    82     char ch[2];
    83     scanf("%s",ch);
    84     int a,b,c;
    85     if(ch[0] == 'Q'){
    86         scanf("%d %d", &a,&b);
    87         printf("%lld
    ",query(a,b,1));
    88     }
    89     else{
    90         scanf("%d %d %d",&a,&b,&c);
    91         cin>>a>>b>>c;
    92         update(c,a,b,1);
    93         }
    94     }
    95     
    96     return 0;
    97 }

    还有一种较好理解的方法:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstring>
     7 using namespace std;
     8 typedef long long LL;
     9 inline LL read(){
    10     LL x=0,f=1;char ch=getchar();
    11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    13     return x*f;
    14 }
    15 const LL maxn=100005;
    16 struct node{
    17     LL num;
    18     LL l,r;
    19     LL lc,rc;
    20     LL sum,lazy;
    21 }seg[maxn*8];
    22 LL a[maxn];
    23 LL N,M,tot=1;
    24 inline void updata_son(LL root){
    25     LL d=seg[root].lazy;
    26     if(d!=0){
    27         LL lson=seg[root].lc; LL rson=seg[root].rc;
    28         seg[lson].lazy+=d; seg[rson].lazy+=d; seg[root].lazy=0;
    29         seg[lson].sum+=d*(seg[lson].r-seg[lson].l+1);
    30         seg[rson].sum+=d*(seg[rson].r-seg[rson].l+1);
    31         
    32     }    
    33 }
    34 inline void Build(LL root,LL l,LL r){
    35     seg[root].num=root; 
    36     seg[root].l=l; seg[root].r=r;
    37     if(l==r){
    38         seg[root].sum=a[l];
    39         return ;
    40     }
    41     LL mid=(l+r)>>1;
    42     seg[root].lc=++tot; Build(tot,l,mid);
    43     seg[root].rc=++tot; Build(tot,mid+1,r);
    44     seg[root].sum=seg[seg[root].lc].sum+seg[seg[root].rc].sum;
    45 }
    46 inline LL query(LL root,LL l,LL r){
    47     if(l<=seg[root].l&&seg[root].r<=r){
    48         return seg[root].sum;
    49     }
    50     updata_son(root);
    51     LL ans=0;
    52     LL mid=(seg[root].l+seg[root].r)>>1;
    53     if(l<=mid) ans+=query(seg[root].lc,l,r);
    54     if(mid+1<=r) ans+=query(seg[root].rc,l,r);
    55     return ans;
    56 }
    57 
    58 inline void change(LL root,LL l,LL r,LL delta){
    59     if(l<=seg[root].l&&seg[root].r<=r){
    60         seg[root].sum+=(seg[root].r-seg[root].l+1)*delta;
    61         seg[root].lazy+=delta;
    62         return ;
    63     }    
    64     updata_son(root);
    65     LL mid=(seg[root].l+seg[root].r)>>1;
    66     if(l<=mid) change(seg[root].lc,l,r,delta);
    67     if(mid+1<=r) change(seg[root].rc,l,r,delta);
    68     seg[root].sum=seg[seg[root].lc].sum+seg[seg[root].rc].sum;
    69 }
    70 int main(){
    71     N=read(); M=read();
    72     for(LL i=1;i<=N;i++) a[i]=read();
    73     Build(1,1,N);
    74     LL ll,rr,de;
    75     char x[2];
    76     for(LL i=1;i<=M;i++){
    77         scanf("%s",x);  
    78         if(x[0]=='C'){
    79             ll=read(); rr=read(); de=read();
    80             change(1,ll,rr,de);
    81             continue;
    82         }
    83         if(x[0]=='Q'){
    84             ll=read(); rr=read();
    85             printf("%lld
    ",query(1,ll,rr));
    86         }
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    为自己的应用程序添加脚本支持
    关于Excel VBA程序的界面编程及其他
    下载JAVA SDK 1.5
    在软件产品中使用VBA的软件和企业
    VBHelper:坚守脚本(转载)
    Google Desktop Search试用手记
    几个不错的开源的.net界面控件
    C++强大背后
    extern用法详解
    条款1:尽量用const和inline而不用#define
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/4626597.html
Copyright © 2020-2023  润新知