线段树基础合集
来源:互联网 发布:阿里云cdn价格下调25 编辑:程序博客网 时间:2024/06/18 12:59
线段树基础合集
codevs上的一些题,是线段树入门(裸)题,比较全面。
包括:
1080:单点修改,区间求和
1081:区间add,询问单点值
1082:区间add,区间求和
4919:复杂一点的区间修改,区间求和
4927:区间add,区间set,区间求和
另外还有我不会的5037
,大佬说是分块做?
CodeVS-1080
裸地基本线段树,当个板子吧。
#include <iostream>#include <cstdio>#include <algorithm>#include <cstdlib>#include <cstring>#include <cmath>#include <vector>#include <queue>#include <stack>#include <iomanip>#include <string>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int MAXN = 100007;const int MA_XN=207;const int oo = 2000000007;const long long int loo = 2000000000000000007ll;typedef long long int ll;typedef struct{ int data; int lazy;} tree;tree sum[MAXN<<2];void PushUP(int rt){ sum[rt].data=sum[rt<<1].data+sum[rt<<1|1].data;}void build (int l,int r,int rt){ if ( l == r ) { int ttt; scanf("%d",&ttt); sum[rt].data=ttt; return; } int m = ( l + r ) >> 1; build (lson); build (rson); PushUP ( rt );}void update(int p,int num,int l,int r,int rt){ if(l==r) { sum[rt].data+=num; return; } int m=(l+r)>>1; if(p<=m) { update(p,num,lson); } if(p>m) { update(p,num,rson); } PushUP(rt);}ll query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) { return sum[rt].data; } int m=(l+r)>>1; ll res=0; if(L<=m) res+=query(L,R,lson); if(m<R) res+=query(L,R,rson); return res;}int main (){ int n; while(~scanf("%d",&n)) { memset(sum,0,sizeof(sum)); build(1,n,1); int m; scanf("%d",&m); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(a==1) { //加法 update(b,c,1,n,1); } else { int res=query(b,c,1,n,1); printf("%d\n",res); } } } return 0;}
CodeVS-1081
这题很无聊,询问单点值。直接参考1082的代码吧。
CodeVS-1082
基本的lazy标记使用。
#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <string>#include <cstring>#include <vector>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#include <iomanip>#define _ ios_base::sync_with_stdio(0),cin.tie(0)#define M(a,b) memset(a,b,sizeof(a))#define N n#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int MAXN=200007;const int oo=0x3f3f3f3f;typedef long long LL;const LL loo=4223372036854775807ll;typedef long double LB;const LL mod=1e9+7;const double eps=1e-6;struct SegmentTree{ LL sum; int lazy;}stree[4*MAXN];void pushup(int rt){ stree[rt].sum=stree[rt<<1].sum+stree[rt<<1|1].sum;}void pushdown(int rt, int m){ if(stree[rt].lazy!=0) { stree[rt<<1].sum+=LL(m-(m>>1))*stree[rt].lazy; stree[rt<<1|1].sum+=LL(m>>1)*stree[rt].lazy; stree[rt<<1].lazy+=stree[rt].lazy; stree[rt<<1|1].lazy+=stree[rt].lazy; stree[rt].lazy=0; }}void build(int l, int r, int rt){ if(l==r) { int tmp;scanf("%d", &tmp); stree[rt].sum=tmp; stree[rt].lazy=0; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt);}void update(int L, int R, int c, int l, int r, int rt){ if(L<=l&&r<=R) { stree[rt].sum+=LL(r-l+1)*c; stree[rt].lazy+=c; return; } pushdown(rt, r-l+1); int m=(l+r)>>1; if(L<=m) update(L, R, c, lson); if(m<R) update(L, R, c, rson); pushup(rt);}LL query(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) { return stree[rt].sum; } pushdown(rt, r-l+1); int m=(l+r)>>1; LL res=0; if(L<=m) res+=query(L,R, lson); if(m<R) res+=query(L, R, rson); return res;}int main(int argc, char *argv[]){ int m, n; while(scanf("%d", &n)==1) { build(1, n, 1); int m;scanf("%d", &m); while(m--) { int cz;scanf("%d", &cz); if(cz==1) { int l, r, c;scanf("%d%d%d", &l, &r, &c); update(l, r, c, 1, n, 1); } else { int l, r;scanf("%d%d", &l, &r); printf("%lld\n", query(l, r, 1, n, 1)); } } } return 0;}
CodeVS-4919
复杂一点的区间修改,问多少数能被7整除。
因为涉及区间的加法,很容易想到,加法相当于shift操作。线段树的每个点上开一个长度7的数组,记录区间内模7余0123456的数分别有多少个。区间加法相当于shift操作。合并直接合并左右区间对应余数的个数即可。配合lazy使用。
另注:5037跟这题表面很像,实际这题的方法用不了。我表示无能为力。
#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <string>#include <cstring>#include <vector>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#include <iomanip>#define _ ios_base::sync_with_stdio(0),cin.tie(0)#define M(a,b) memset(a,b,sizeof(a))#define N n#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int MAXN=200007;const int oo=0x3f3f3f3f;typedef long long LL;const LL loo=4223372036854775807ll;typedef long double LB;const LL mod=1e9+7;const double eps=1e-6;struct SegmentTree{ LL sum[7]; int lazy;}stree[4*MAXN];void pushup(int rt){ for(int i=0;i<7;i++) stree[rt].sum[i]=stree[rt<<1].sum[i]+stree[rt<<1|1].sum[i];}void pushdown(int rt){ if(stree[rt].lazy!=0) { int py=stree[rt].lazy; int tmp[7]; for(int i=0;i<7;i++) tmp[i]=stree[rt<<1].sum[i]; for(int i=0;i<7;i++) stree[rt<<1].sum[(i+py)%7]=tmp[i]; for(int i=0;i<7;i++) tmp[i]=stree[rt<<1|1].sum[i]; for(int i=0;i<7;i++) stree[rt<<1|1].sum[(i+py)%7]=tmp[i]; stree[rt<<1].lazy+=stree[rt].lazy; stree[rt<<1|1].lazy+=stree[rt].lazy; stree[rt].lazy=0; }}void build(int l, int r, int rt){ if(l==r) { for(int i=0;i<7;i++) stree[rt].sum[i]=0; int tmp;scanf("%d", &tmp); stree[rt].sum[tmp%7]=1; stree[rt].lazy=0; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt);}void update(int L, int R, int c, int l, int r, int rt){ if(L<=l&&r<=R) { int py=c; int tmp[7]; for(int i=0;i<7;i++) tmp[i]=stree[rt].sum[i]; for(int i=0;i<7;i++) stree[rt].sum[(i+py)%7]=tmp[i]; stree[rt].lazy+=c; return; } pushdown(rt); int m=(l+r)>>1; if(L<=m) update(L, R, c, lson); if(m<R) update(L, R, c, rson); pushup(rt);}LL query(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) { return stree[rt].sum[0]; } pushdown(rt); int m=(l+r)>>1; LL res=0; if(L<=m) res+=query(L, R, lson); if(m<R) res+=query(L, R, rson); return res;}int main(int argc, char *argv[]){ int m, n; while(scanf("%d", &n)==1) { build(1, n, 1); int m;scanf("%d", &m); while(m--) { char cz[10];scanf("%s", cz); if(cz[0]=='a') { int l, r, c;scanf("%d%d%d", &l, &r, &c); update(l, r, c%7, 1, n, 1); } else { int l, r;scanf("%d%d", &l, &r); printf("%lld\n", query(l, r, 1, n, 1)); } } } return 0;}
CodeVS-4927
这题涉及两个lazy标记的传递顺序问题。set的优先级要高于add:比如一些数,我先add,在set,那么add便没用了;而我先set,在add,那么这个add也是有用的,仍需要向下传递。
按我的代码风格,每添加一个标记,立马修改本区间的值(sum,max,min),并设置本区间lazy有效;若添加的标记是set,那么置本区间add无效;待查询时,要是查询本区间,那么不传递lazy,查询子区间时经过本区间,那么向下传递lazy。
向下传递lazy时注意:若set有效,那么先传递set,并置子区间的add无效;若本区间set与add同时有效,说明本区间先set后add过,两标记都要向下传递!我最开始犯了两个错误:1是传递set后将本区间的add也置为无效了;2是传递完set就return了。因为我的代码风格,set后置本区间add无效(子区间也是如此,因为向下传递set时置了add无效),所以addset同时出现一定是先set后add。
#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <string>#include <cstring>#include <vector>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#include <iomanip>#define _ ios_base::sync_with_stdio(0),cin.tie(0)#define M(a,b) memset(a,b,sizeof(a))#define N n#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int MAXN=200007;const int oo=0x3f3f3f3f;typedef long long LL;const LL loo=4223372036854775807ll;typedef long double LB;const LL mod=1e9+7;const double eps=1e-6;struct SegmentTree{ LL sum; LL lazy; LL set; bool sset; LL mi; LL ma;}stree[4*MAXN];void pushup(int rt){ stree[rt].sum=stree[rt<<1].sum+stree[rt<<1|1].sum; stree[rt].mi=min(stree[rt<<1].mi, stree[rt<<1|1].mi); stree[rt].ma=max(stree[rt<<1].ma, stree[rt<<1|1].ma);}void pushdown(int rt, int m){ if(stree[rt].sset==true) { LL tmp=stree[rt].set;stree[rt].set=0;stree[rt].sset=false; stree[rt<<1].sum=tmp*(m-(m>>1)); stree[rt<<1|1].sum=tmp*(m>>1); stree[rt<<1].ma=stree[rt<<1|1].ma=tmp; stree[rt<<1].mi=stree[rt<<1|1].mi=tmp; stree[rt<<1].set=stree[rt<<1|1].set=tmp; stree[rt<<1].sset=stree[rt<<1|1].sset=true; /*stree[rt].lazy=0;*/stree[rt<<1].lazy=0;stree[rt<<1|1].lazy=0; //return; } if(stree[rt].lazy!=0) { LL tmp=stree[rt].lazy;stree[rt].lazy=0; stree[rt<<1].sum+=tmp*(m-(m>>1)); stree[rt<<1|1].sum+=tmp*(m>>1); stree[rt<<1].ma+=tmp;stree[rt<<1|1].ma+=tmp; stree[rt<<1].mi+=tmp;stree[rt<<1|1].mi+=tmp; stree[rt<<1].lazy+=tmp;stree[rt<<1|1].lazy+=tmp; }}void build(int l, int r, int rt){ if(l==r) { LL tmp;scanf("%lld", &tmp); stree[rt].sum=stree[rt].ma=stree[rt].mi=tmp; stree[rt].lazy=stree[rt].set=stree[rt].sset=0; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt);}void update_set(int L, int R, LL s, int l, int r, int rt){ if(L<=l&&r<=R) { stree[rt].sum=(LL)s*(r-l+1); stree[rt].ma=stree[rt].mi=s; stree[rt].set=s; stree[rt].sset=true; stree[rt].lazy=0; pushdown(rt, r-l+1); return; } pushdown(rt, r-l+1); int m=(l+r)>>1; if(L<=m) update_set(L, R, s, lson); if(m<R) update_set(L, R, s, rson); pushup(rt);}void update_add(int L, int R, LL c, int l, int r, int rt){ if(L<=l&&r<=R) { stree[rt].sum+=(LL)c*(r-l+1); stree[rt].ma+=c; stree[rt].mi+=c; stree[rt].lazy+=c; pushdown(rt, r-l+1); return; } pushdown(rt, r-l+1); int m=(l+r)>>1; if(L<=m) update_add(L, R, c, lson); if(m<R) update_add(L, R, c, rson); pushup(rt);}LL query_sum(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) { return stree[rt].sum; } pushdown(rt, r-l+1); int m=(l+r)>>1; LL res=0; if(L<=m) res+=query_sum(L, R, lson); if(m<R) res+=query_sum(L, R, rson); return res;}LL query_ma(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) { return stree[rt].ma; } pushdown(rt, r-l+1); int m=(l+r)>>1; LL res=-loo; if(L<=m) res=max(res, query_ma(L, R, lson)); if(m<R) res=max(res, query_ma(L, R, rson)); return res;}LL query_mi(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) { return stree[rt].mi; } pushdown(rt, r-l+1); int m=(l+r)>>1; LL res=loo; if(L<=m) res=min(res, query_mi(L, R, lson)); if(m<R) res=min(res, query_mi(L, R, rson)); return res;}int main(int argc, char *argv[]){ int m, n; while(scanf("%d%d", &n, &m)==2) { M(stree, 0); build(1, n, 1); while(m--) { char cz[10];scanf("%s", cz); if(cz[1]=='d') { int l, r;LL c;scanf("%d%d%lld", &l, &r, &c); update_add(l, r, c, 1, n, 1); } else if(cz[1]=='e') { int l, r;LL c;scanf("%d%d%lld", &l, &r, &c); update_set(l, r, c, 1, n, 1); } else if(cz[1]=='u') { int l, r;scanf("%d%d", &l, &r); printf("%lld\n", query_sum(l, r, 1, n, 1)); } else if(cz[1]=='a') { int l, r;scanf("%d%d", &l, &r); printf("%lld\n", query_ma(l, r, 1, n, 1)); } else { int l, r;scanf("%d%d", &l, &r); printf("%lld\n", query_mi(l, r, 1, n, 1)); } } } return 0;}
- 线段树基础合集
- 线段树题目合集
- 线段树模板及专题合集-----不断更新中
- 基础C++用法(合集)
- 基础C++概述 (合集)
- 【数论基础算法合集】
- Android-动画基础合集
- 线段树模板合集--单点替换,区间替换,区间增加3种情况
- 线段树基础
- 基础线段树
- 线段树基础题
- 线段树 基础
- 线段树基础篇
- POJ2528线段树基础
- 线段树基础
- 线段树基础 poj2104
- 线段树基础 poj2352
- 线段树基础
- Ubuntu下安装Python2.7.5
- hustoj的搭建
- STM32之SysTick定时器
- Python中is和==的区别
- pandas1
- 线段树基础合集
- 大话数据结构(八)Java程序——双向链表的实现 线性链表——双向链表
- 323_棋盘问题
- 带有参数的main函数
- NOIP 2014 Senior 2
- jQuery——使用插件
- python 简单的抓网页
- busybox编译的博客
- python flask安装