zoukankan      html  css  js  c++  java
  • poj3468A Simple Problem with Integers线段树入门+区间更新

    题意:
    C:对区间[l,r]每一个数+c;
    Q:查询区间[l,r]的所有元素的总和。

    线段树修改和查找的时间复杂度都是O(logn)。
    线段树基本思想:分治。
    线段树基本操作:建树、区间查询(最值;和)、区间修改(更新)、单点修改、单点查询。

    注意这题,输入说是一行 N、q 单组输入,但是会TLE,多组输入才可以AC。

    AC代码:

      1 //题意:
      2 //C:对区间[l,r]每一个数+c;
      3 // Q:查询区间[l,r]的所有元素的总和。
      4 
      5 //线段树修改和查找的时间复杂度都是O(logn)。
      6 //线段树基本思想:分治。
      7 //线段树基本操作:建树、区间查询(最值;和)、区间修改(更新)、单点修改、单点查询。
      8 
      9 #include<stdio.h>
     10 #include<string.h>
     11 #include<iostream>
     12 #include<queue>
     13 #include<map>
     14 #include<stack>
     15 #include<queue>
     16 #include<algorithm>
     17 #include<cmath>
     18 
     19 using namespace std;
     20 #define inf 0x3f3f3f3f;
     21 #define pi acos(-1.0)
     22 #define mem(a,b) memset(a,b,sizeof(a))
     23 #define eps 1e-9
     24 typedef long long ll;
     25 
     26 const int N=1e5+20;
     27 ll a[N<<2],lazy[N<<2];//需要开到节点的四倍大小
     28 
     29 void build(int L,int R,int i)
     30 {
     31     if(L==R)//当左右结点相同的时候,说明该节点可以建树,输入即可。
     32     {
     33         scanf("%lld",&a[i]);//即为叶子结点
     34         return;//因为已经确定这个点可以输入了,也就类似叶结点,返回函数上次调用的地方即可。
     35     }
     36 
     37     //否则往下继续找
     38     int mid=(L+R)>>1;
     39     build(L,mid,i<<1);//递归建立左子树
     40     build(mid+1,R,i<<1|1);//递归建立右子树
     41     a[i]=a[i<<1]+a[i<<1|1];//统计该点(i)的左子树和右子树之和
     42     //a这个操作也可以另外写到一个函数pushup中(即pushup(i)),这个看自己怎么写代码
     43     //节点数据向上更新
     44 
     45     //根据题意写,这一题是求区间和,之前左区间和右区间相加即可
     46     //例如如果求区间内最大值,则写成:a[i]=max(a[i<<1],a[i<<1|1]);
     47 }
     48 
     49 void pushdown(int i,int len)//节点懒惰标记下推
     50 {
     51     if(lazy[i])//如果懒惰标记为真,说明之前有过懒惰标记,现在需要进行更新
     52     {
     53         lazy[i<<1]+=lazy[i];//懒惰标记往左结点传
     54         lazy[i<<1|1]+=lazy[i];//懒惰标记往右结点传
     55         //左右用 |1 区分
     56         //因为求区间和,所以当区间内每个元素加上一个值时,区间的和也加上这个值
     57         //对于区间求和, 原数组值需要加上lazy标记*子树所统计的区间长度
     58         a[i<<1]+=lazy[i]*(len-(len>>1));//(len-(len>>1)是左区间的长度
     59         a[i<<1|1]+=lazy[i]*(len>>1);//(len>>1)是右区间的长度
     60         lazy[i]=0;//由于懒惰标记向下传递,所以当前节点的懒惰标记取消
     61     }
     62     //对于区间求最大值, 子树的值不需要乘以长度, 所以不需要传递参数区间长度len。
     63 }
     64 
     65 //注意:
     66 // 1、单点更新, 不需要用到lazy标记
     67 // 2、成段(区间)更新, 需要用到lazy标记来提高时间效率
     68 void update(int x,int y,int L,int R,int i,int pluss)
     69 {
     70     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     71         //范围缩小到left和right之间
     72     {
     73         a[i]+=pluss*(R-L+1);
     74         lazy[i]+=pluss;
     75         return;
     76     }
     77     pushdown(i,R-L+1);
     78     int mid=(L+R)>>1;
     79 
     80     //更新区间
     81     if(x<=mid)//更新左区间
     82         update(x,y,L,mid,i<<1,pluss);
     83     if(y>mid)//更新右区间
     84         update(x,y,mid+1,R,i<<1|1,pluss);
     85 
     86     //更新结点值
     87     a[i]=a[i<<1]+a[i<<1|1];
     88 }
     89 
     90 ll query(int x,int y,int L,int R,int i)//查询操作
     91 {
     92     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     93         return a[i];//返回当前值
     94     pushdown(i,R-L+1);
     95     int mid=(L+R)>>1;
     96     ll ans=0;
     97     if(x<=mid)//递归查询左子树内部的的区间值
     98         ans+=query(x,y,L,mid,i<<1);
     99     if(y>mid)//递归查询右子树内部的的区间值
    100         ans+=query(x,y,mid+1,R,i<<1|1);
    101     return ans;//返回题目所需的区间和(左+右)
    102 }
    103 
    104 int main()
    105 {
    106     int n,q;
    107     while(~scanf("%d %d",&n,&q))
    108     {
    109         mem(lazy,0);//如果多组数据lazy数组需要进行清空
    110         mem(a,0);
    111         build(1,n,1);//开始建树,传入树的总区间(传入最左端点,最右端点)和树的根节点
    112         //建树的过程中输入每一个节点
    113         for(int i=1;i<=q;i++)
    114         {
    115             char ch;
    116             getchar();//吸收每次读入的空格
    117             scanf("%c",&ch);
    118             if(ch=='Q')//询问区间内的和
    119             {
    120                 int x,y;
    121                 scanf("%d %d",&x,&y);
    122                 ll ans=query(x,y,1,n,1);
    123                 printf("%lld\n",ans);
    124             }else if(ch=='C')//往区间内每一个数上都插入pluss
    125             {
    126                 int x,y,z;
    127                 scanf("%d %d %d",&x,&y,&z);
    128                 update(x,y,1,n,1,z);
    129             }
    130         }
    131     }
    132     return 0;
    133 }
    View Code
  • 相关阅读:
    MySQL8 Keepalived+双主
    Last_SQL_Errno: 1050 Last_SQL_Error: Error 'Table 'events' already exists' on query. Default database: 'eygle'. Query: 'create table events
    [MY-011522] [Repl] Plugin group_replication reported: 'The member contains transactions not present in the group.
    MYSQL8 裸机搭主从
    MY-011292 MY-011300 MY-013597 MY-011300
    RHLE8 docker安装
    docker harbor x509: certificate signed by unknown authority action: push: unauthorized to access repository
    harbor配置https访问
    action: push: unauthorized to access repository
    unlock DDIC for HANADB
  • 原文地址:https://www.cnblogs.com/OFSHK/p/11285667.html
Copyright © 2011-2022 走看看