• poj 3468 A Simple Problem with Integers(线段树区间lazy标记修改or树状数组)


    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.
    解题思路:题意很清楚,大区间修改和询问:线段树+lazy懒标记,or树状数组,详解在代码里,注意求和用long long类型!
    AC代码一之线段树懒标记(2500ms):
     1 #include<string.h>
     2 #include<cstdio>
     3 using namespace std;
     4 typedef long long LL;
     5 const int maxn=100005;
     6 int n,q,a,b;LL c,s[maxn],lazy[maxn<<2],sum[maxn<<2];char ch;
     7 void build(int l,int r,int x){//建树基本操作
     8     int mid=(l+r)>>1;
     9     if(l==r){sum[x]=s[mid];return;}
    10     build(l,mid,x<<1);
    11     build(mid+1,r,x<<1|1);
    12     sum[x]=sum[x<<1]+sum[x<<1|1];
    13 }
    14 void push_down(int x,int len){//下放懒标记
    15     if(lazy[x]){
    16         lazy[x<<1]+=lazy[x];//延迟修改量是叠加的,沿着子树可以继续更新下去
    17         lazy[x<<1|1]+=lazy[x];
    18         sum[x<<1]+=(LL)(len-(len>>1))*lazy[x];//更新左子节点的值:加上左区间长度乘上父节点的懒标记
    19         sum[x<<1|1]+=(LL)(len>>1)*lazy[x];//更新右子节点的值:加上右区间长度乘上父节点的懒标记
    20         lazy[x]=0;//同时标记父节点已经修改完成,即置懒标记为0
    21     }
    22 }
    23 void modify(int l,int r,int x,LL c){
    24     if(a<=l&&r<=b){//如果[a,b]包含了当前子区间[l,r],则直接进行懒标记,不再递归下去
    25         lazy[x]+=c;//叠加懒标记值
    26         sum[x]+=(LL)c*(r-l+1);//同时累加修改值乘上当前子区间的长度
    27         return;
    28     }
    29     push_down(x,r-l+1);//如果修改区间不包含当前子区间,并且当前子区间有懒标记,则下放懒标记
    30     int mid=(l+r)>>1;
    31     if(b<=mid)modify(l,mid,x<<1,c);
    32     else if(a>mid)modify(mid+1,r,x<<1|1,c);
    33     else{
    34         modify(l,mid,x<<1,c);
    35         modify(mid+1,r,x<<1|1,c);
    36     }
    37     sum[x]=sum[x<<1]+sum[x<<1|1];//修改某个区间后还要向上更新父节点的值
    38 }
    39 LL query(int l,int r,int x){
    40     if(a<=l&&r<=b)return sum[x];//如果访问的区间[a,b]包含子区间[l,r],直接返回返回当前区间的值
    41     int mid=(l+r)>>1;
    42     push_down(x,r-l+1);//如果不包含子区间,并且当前节点有被懒标记,则应下放懒标记,因为查询的区间可能更小(最小到叶子节点),为避免少计算,还要这步操作,此时就不用向上更新了,修改区间值才要
    43     if(b<=mid)return query(l,mid,x<<1);
    44     else if(a>mid)return query(mid+1,r,x<<1|1);
    45     else return query(l,mid,x<<1)+query(mid+1,r,x<<1|1);
    46 }
    47 int main(){
    48     scanf("%d%d",&n,&q);
    49     for(int i=1;i<=n;++i)scanf("%lld",&s[i]);
    50     memset(lazy,0,sizeof(lazy));//注意:将每个节点的懒标记都标记为0
    51     build(1,n,1);//建树
    52     while(q--){
    53         getchar();//吃掉回车符避免对字符输入的影响
    54         scanf("%c",&ch);
    55         if(ch=='Q'){
    56             scanf("%d%d",&a,&b);
    57             printf("%lld
    ",query(1,n,1));
    58         }
    59         else{
    60             scanf("%d%d%lld",&a,&b,&c);
    61             modify(1,n,1,c);
    62         }
    63     }
    64     return 0;
    65 }

     AC代码二之树状数组(2125ms):裸题,套一下树状数组区间查询和区间修改模板即可。

     1 #include<string.h>
     2 #include<cstdio>
     3 typedef long long LL;
     4 const int maxn=100005;
     5 LL n,q,l,r,k,val[maxn],sum1[maxn],sum2[maxn];char op;
     6 void add(LL *sum,LL x,LL val){
     7     while(x<=n){sum[x]+=val;x+=(x&-x);}
     8 }
     9 LL get_sum(LL *sum,LL x){
    10     LL ans=0;
    11     while(x>0){ans+=sum[x];x-=(x&-x);}
    12     return ans;
    13 }
    14 LL ask(LL x){
    15     return x*get_sum(sum1,x)-get_sum(sum2,x);
    16 }
    17 int main(){
    18     while(~scanf("%lld%lld",&n,&q)){
    19         memset(sum1,0,sizeof(sum1));
    20         memset(sum2,0,sizeof(sum2));
    21         memset(val,0,sizeof(val));
    22         for(LL i=1;i<=n;++i){
    23             scanf("%lld",&val[i]);
    24             add(sum1,i,val[i]-val[i-1]);//维护差分数组
    25             add(sum2,i,(i-1)*(val[i]-val[i-1]));
    26         }
    27         while(q--){
    28             getchar();//吸收回车符避免对单个字符读取的影响
    29             scanf("%c",&op);
    30             if(op=='C'){
    31                 scanf("%lld%lld%lld",&l,&r,&k);
    32                 add(sum1,l,k),add(sum1,r+1,-k);
    33                 add(sum2,l,(l-1)*k);add(sum2,r+1,-r*k);
    34             }
    35             else{
    36                 scanf("%lld%lld",&l,&r);
    37                 printf("%lld
    ",ask(r)-ask(l-1));//区间查询[1,r]-[1,l-1]=[l,r]
    38             }
    39         }
    40     }
    41     return 0;
    42 }
  • 相关阅读:
    【读书笔记】构建之法(CH7~CH8)
    【课后作业】软件创新
    【个人开发】词频统计
    【读书笔记】没有银弹
    【个人开发】词频统计-代码规范
    【个人开发】词频统计-文档设计
    GitBook 使用
    Android NDK 入门与实践
    Python 爬虫实战(一):使用 requests 和 BeautifulSoup
    手把手教你做个人 app
  • 原文地址:https://www.cnblogs.com/acgoto/p/9441744.html
Copyright © 2020-2023  润新知