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 }
注意一下:
区间修改问的是
把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 }
2、A的基础上 + B
题目和板子:
https://www.cnblogs.com/OFSHK/p/11285667.html
这题用树状数组更快一点,之后补上树状数组的板子 ~
参考学习博客:https://blog.csdn.net/lml11111/article/details/83032921