• HihoCoder1078-线段树的区间修改-线段树区间修改、查询-模板题


    题意:

    中文题、板子题。

    AC代码:

      1 #include<iostream>
      2 #include<stdio.h>
      3 #include<map>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<stack>
      7 #include<cmath>
      8 #include<string.h>
      9 
     10 using namespace std;
     11 #define mem(p,b) memset(p,b,sizeof(p))
     12 #define inf 0x3f3f3f3f
     13 typedef long long ll;
     14 
     15 const int N=1e5+20;
     16 ll a[N<<2],lazy[N<<2];//需要开到节点的四倍大小
     17 
     18 void build(int L,int R,int i)
     19 {
     20     if(L==R)//当左右结点相同的时候,说明该节点可以建树,输入即可。
     21     {
     22         scanf("%lld",&a[i]);//即为叶子结点
     23         return;//因为已经确定这个点可以输入了,也就类似叶结点,返回函数上次调用的地方即可。
     24     }
     25 
     26     //否则往下继续找
     27     int mid=(L+R)>>1;
     28     build(L,mid,i<<1);//递归建立左子树
     29     build(mid+1,R,i<<1|1);//递归建立右子树
     30     a[i]=a[i<<1]+a[i<<1|1];//统计该点(i)的左子树和右子树之和
     31     //a这个操作也可以另外写到一个函数pushup中(即pushup(i)),这个看自己怎么写代码
     32     //节点数据向上更新
     33 
     34     //根据题意写,这一题是求区间和,之前左区间和右区间相加即可
     35     //例如如果求区间内最大值,则写成:a[i]=max(a[i<<1],a[i<<1|1]);
     36 }
     37 
     38 void pushdown(int i,int len)//节点懒惰标记下推
     39 {
     40     if(lazy[i])//如果懒惰标记为真,说明之前有过懒惰标记,现在需要进行更新
     41     {
     42 //        lazy[i<<1]+=lazy[i];//懒惰标记往左结点传
     43 //        lazy[i<<1|1]+=lazy[i];//懒惰标记往右结点传
     44 //        //左右用 |1 区分
     45 //        //因为求区间和,所以当区间内每个元素加上一个值时,区间的和也加上这个值
     46 //        //对于区间求和, 原数组值需要加上lazy标记*子树所统计的区间长度
     47 //        a[i<<1]+=lazy[i]*(len-(len>>1));//(len-(len>>1)是左区间的长度
     48 //        a[i<<1|1]+=lazy[i]*(len>>1);//(len>>1)是右区间的长度
     49 //        lazy[i]=0;//由于懒惰标记向下传递,所以当前节点的懒惰标记取消
     50         lazy[i<<1]=lazy[i];
     51         lazy[i<<1|1]=lazy[i];
     52         a[i<<1]=lazy[i]*(len-(len>>1));
     53         a[i<<1|1]=lazy[i]*(len>>1);
     54         lazy[i]=0;
     55     }
     56     //对于区间求最大值, 子树的值不需要乘以长度, 所以不需要传递参数区间长度len。
     57 }
     58 
     59 //注意:
     60 // 1、单点更新, 不需要用到lazy标记
     61 // 2、成段(区间)更新, 需要用到lazy标记来提高时间效率
     62 void update(int x,int y,int L,int R,int i,int pluss)
     63 {
     64     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     65         //范围缩小到left和right之间
     66     {
     67 //        a[i]+=pluss*(R-L+1);
     68 //        lazy[i]+=pluss;
     69         a[i]=pluss*(R-L+1);
     70         lazy[i]=pluss;
     71         return;
     72     }
     73     pushdown(i,R-L+1);
     74     int mid=(L+R)>>1;
     75 
     76     //更新区间
     77     if(x<=mid)//更新左区间
     78         update(x,y,L,mid,i<<1,pluss);
     79     if(y>mid)//更新右区间
     80         update(x,y,mid+1,R,i<<1|1,pluss);
     81 
     82     //更新结点值
     83     a[i]=a[i<<1]+a[i<<1|1];
     84 }
     85 
     86 ll query(int x,int y,int L,int R,int i)//查询操作
     87 {
     88     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     89         return a[i];//返回当前值
     90     pushdown(i,R-L+1);
     91     int mid=(L+R)>>1;
     92     ll ans=0;
     93     if(x<=mid)//递归查询左子树内部的的区间值
     94         ans+=query(x,y,L,mid,i<<1);
     95     if(y>mid)//递归查询右子树内部的的区间值
     96         ans+=query(x,y,mid+1,R,i<<1|1);
     97     return ans;//返回题目所需的区间和(左+右)
     98 }
     99 
    100 int main()
    101 {
    102     int n,q;
    103     scanf("%d",&n);
    104     build(1,n,1);
    105     scanf("%d",&q);
    106     for(int i=1;i<=q;i++)
    107     {
    108         int t,x,y;
    109         scanf("%d %d %d",&t,&x,&y);
    110         if(t==0)
    111             printf("%lld
    ",query(x,y,1,n,1));
    112         else
    113         {
    114             int c;
    115             scanf("%d",&c);
    116             update(x,y,1,n,1,c);//修改为c,不是加上
    117         }
    118     }
    119     return 0;
    120 }
    View Code

    注意一下:

    区间修改问的是

    把A直接修改为B,还是在A的基础上 + B ;

    1、把A直接修改为B

    本题就是模板;

    板子:

      1 #include<iostream>
      2 #include<stdio.h>
      3 #include<map>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<stack>
      7 #include<cmath>
      8 #include<string.h>
      9 
     10 using namespace std;
     11 #define mem(p,b) memset(p,b,sizeof(p))
     12 #define inf 0x3f3f3f3f
     13 typedef long long ll;
     14 
     15 const int N=1e5+20;
     16 ll a[N<<2],lazy[N<<2];//需要开到节点的四倍大小
     17 
     18 void build(int L,int R,int i)
     19 {
     20     if(L==R)//当左右结点相同的时候,说明该节点可以建树,输入即可。
     21     {
     22         scanf("%lld",&a[i]);//即为叶子结点
     23         return;//因为已经确定这个点可以输入了,也就类似叶结点,返回函数上次调用的地方即可。
     24     }
     25 
     26     //否则往下继续找
     27     int mid=(L+R)>>1;
     28     build(L,mid,i<<1);//递归建立左子树
     29     build(mid+1,R,i<<1|1);//递归建立右子树
     30     a[i]=a[i<<1]+a[i<<1|1];//统计该点(i)的左子树和右子树之和
     31     //a这个操作也可以另外写到一个函数pushup中(即pushup(i)),这个看自己怎么写代码
     32     //节点数据向上更新
     33 
     34     //根据题意写,这一题是求区间和,之前左区间和右区间相加即可
     35     //例如如果求区间内最大值,则写成:a[i]=max(a[i<<1],a[i<<1|1]);
     36 }
     37 
     38 void pushdown(int i,int len)//节点懒惰标记下推
     39 {
     40     if(lazy[i])//如果懒惰标记为真,说明之前有过懒惰标记,现在需要进行更新
     41     {
     42 //        lazy[i<<1]+=lazy[i];//懒惰标记往左结点传
     43 //        lazy[i<<1|1]+=lazy[i];//懒惰标记往右结点传
     44 //        //左右用 |1 区分
     45 //        //因为求区间和,所以当区间内每个元素加上一个值时,区间的和也加上这个值
     46 //        //对于区间求和, 原数组值需要加上lazy标记*子树所统计的区间长度
     47 //        a[i<<1]+=lazy[i]*(len-(len>>1));//(len-(len>>1)是左区间的长度
     48 //        a[i<<1|1]+=lazy[i]*(len>>1);//(len>>1)是右区间的长度
     49 //        lazy[i]=0;//由于懒惰标记向下传递,所以当前节点的懒惰标记取消
     50         lazy[i<<1]=lazy[i];
     51         lazy[i<<1|1]=lazy[i];
     52         a[i<<1]=lazy[i]*(len-(len>>1));
     53         a[i<<1|1]=lazy[i]*(len>>1);
     54         lazy[i]=0;
     55     }
     56     //对于区间求最大值, 子树的值不需要乘以长度, 所以不需要传递参数区间长度len。
     57 }
     58 
     59 //注意:
     60 // 1、单点更新, 不需要用到lazy标记
     61 // 2、成段(区间)更新, 需要用到lazy标记来提高时间效率
     62 void update(int x,int y,int L,int R,int i,int pluss)
     63 {
     64     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     65         //范围缩小到left和right之间
     66     {
     67 //        a[i]+=pluss*(R-L+1);
     68 //        lazy[i]+=pluss;
     69         a[i]=pluss*(R-L+1);
     70         lazy[i]=pluss;
     71         return;
     72     }
     73     pushdown(i,R-L+1);
     74     int mid=(L+R)>>1;
     75 
     76     //更新区间
     77     if(x<=mid)//更新左区间
     78         update(x,y,L,mid,i<<1,pluss);
     79     if(y>mid)//更新右区间
     80         update(x,y,mid+1,R,i<<1|1,pluss);
     81 
     82     //更新结点值
     83     a[i]=a[i<<1]+a[i<<1|1];
     84 }
     85 
     86 ll query(int x,int y,int L,int R,int i)//查询操作
     87 {
     88     if(L>=x&&R<=y)//当前节点区间包含在查询区间内
     89         return a[i];//返回当前值
     90     pushdown(i,R-L+1);
     91     int mid=(L+R)>>1;
     92     ll ans=0;
     93     if(x<=mid)//递归查询左子树内部的的区间值
     94         ans+=query(x,y,L,mid,i<<1);
     95     if(y>mid)//递归查询右子树内部的的区间值
     96         ans+=query(x,y,mid+1,R,i<<1|1);
     97     return ans;//返回题目所需的区间和(左+右)
     98 }
     99 
    100 int main()
    101 {
    102     int n,q;
    103     scanf("%d",&n);
    104     build(1,n,1);
    105     scanf("%d",&q);
    106     for(int i=1;i<=q;i++)
    107     {
    108         int t,x,y;
    109         scanf("%d %d %d",&t,&x,&y);
    110         if(t==0)
    111             printf("%lld
    ",query(x,y,1,n,1));
    112         else
    113         {
    114             int c;
    115             scanf("%d",&c);
    116             update(x,y,1,n,1,c);//修改为c,不是加上
    117         }
    118     }
    119     return 0;
    120 }
    View Code

    2、A的基础上 + B 

    题目和板子:

    https://www.cnblogs.com/OFSHK/p/11285667.html

    这题用树状数组更快一点,之后补上树状数组的板子 ~ 

    参考学习博客:https://blog.csdn.net/lml11111/article/details/83032921

  • 相关阅读:
    Ubantu 安装Redis
    传说中的WCF(5):数据协定(a)
    传说中的WCF(4):发送和接收SOAP头
    传说中的WCF(3):多个协定
    传说中的WCF(2):服务协定的那些事儿
    传说中的WCF(1):这东西难学吗?
    Linq教程
    Installutil.exe的位置和路径
    uni-app中对输入框的判断与提示(密码格式为6-12位,必须有大小写字母和数字组成)
    uni-app系列回顾总结----项目国际化
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12919408.html
Copyright © 2020-2023  润新知