• 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 }
  • 相关阅读:
    C# 操作配置文件
    C# Excel操作类
    没有找到 mspdb100.dll 的解决办法
    工厂方法模式
    .Net互操作2
    The certificate used to sign “AppName” has either expired or has been revoked. An updated certificate is required to sign and install the application解决
    手机抓包xcode自带命令行工具配合wireshark实现
    expecting SSH2_MSG_KEX_ECDH_REPLY ssh_dispatch_run_fatal问题解决
    使用ssh-keygen设置ssh无密码登录
    远程复制文件到服务器
  • 原文地址:https://www.cnblogs.com/acgoto/p/9441744.html
Copyright © 2020-2023  润新知