浏览器标题切换
浏览器标题切换end

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\n",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\n",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

 

posted @ 2020-05-19 20:43  抓水母的派大星  阅读(167)  评论(0编辑  收藏  举报