题目链接 [kuangbin带你飞]专题七 线段树
线段树,从入门到模板,呵呵呵~
线段树是acm里一个基本的题型啰,一般用于区间的问题
首先模板:
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x? x=y: x=x const int maxn=1e5+7; struct node{ int l,r; ll lazy,sum; void update(ll x){ sum+=x*(r-l+1); // 更新懒结点,一般的题目只要修改这儿就行了 lazy+=x; } }tree[maxn*4]; int a[maxn]; void push_up(int x){ tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; /// 根据题目要求 } void push_down(int x){ int lazytp=tree[x].lazy; if(lazytp){ tree[x<<1].update(lazytp); tree[x<<1|1].update(lazytp); tree[x].lazy=0; } } void built(int x,int l,int r){ tree[x]=node{l,r,0,0}; if(l==r){ tree[x].sum=a[l]; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } void update(int x,int l,int r,int val){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ tree[x].update(val); } else{ push_down(x); int mid=(L+R)>>1; if(mid>=l) update(x<<1,l,r,val); if(mid<r) update(x<<1|1,l,r,val); push_up(x); } } ll query(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].sum; /// 根据题目要求 } else{ push_down(x); ll ans=0; int mid=(L+R)>>1; if(mid>=l) ans+=query(x<<1,l,r); if(mid<r) ans+=query(x<<1|1,l,r); push_up(x); return ans; } } int main(){ std::ios::sync_with_stdio(false); int n,q; cin>>n>>q; for(int i=1;i<=n;i++){ cin>>a[i]; } built(1,1,n); while(q--){ int c,l,r,k; cin>>c>>l>>r; if(c==1){ cin>>k; update(1,l,r,k); } else{ cout<<query(1,l,r)<<endl; } } return 0; }
加注释的地方就是一般要改的地方啰。
A.
套模板呗,这题懒标记都不要,单点更新,所以我们可以套模板
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) #define Max(x,y) y>x?x=y:x=x char buf[(1 << 22)], *p1 = buf, *p2 = buf; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f; } const int maxn=5e4+7; #define read(x) x=read() int n; int f[maxn]; struct node{ int l,r; ll lazy,sum; void update(ll x){ sum+=x*(r-l+1); lazy+=x; } }tree[maxn*4]; void push_up(int x){ tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; } void push_down(int x){ int lazytp=tree[x].lazy; if(lazytp){ tree[x<<1].update(lazytp); tree[x<<1|1].update(lazytp); tree[x].lazy=0; } } int a[maxn]; void built(int x,int l,int r){ tree[x]=node{l,r,0,0}; if(l==r){ tree[x].sum=f[l]; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } void update(int x,int l,int r,int val){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ tree[x].update(val); } else{ push_down(x); int mid=(L+R)>>1; if(mid>=l) update(x<<1,l,r,val); if(mid<r) update(x<<1|1,l,r,val); push_up(x); } } ll query(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].sum; } else{ push_down(x); ll ans=0; int mid=(L+R)>>1; if(mid>=l) ans+=query(x<<1,l,r); if(mid<r) ans+=query(x<<1|1,l,r); push_up(x); return ans; } } int main() { std::ios::sync_with_stdio(false); int t,ca=0; cin>>t; while(t--){ ca++; mem(f,0); cin>>n; for(int i=1;i<=n;i++){ cin>>f[i]; } built(1,1,n); string ts; int x,y; cout<<"Case "<<ca<<":"<<endl; while(cin>>ts && ts!="End"){ cin>>x>>y; if(ts=="Query"){ cout<<query(1,x,y)<<endl; } else if(ts=="Add"){ update(1,x,x,y); } else if(ts=="Sub"){ update(1,x,x,-y); } } } return 0; }
B.
同样套模板,不要懒标记的,只要更新保存最大值就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x?x=y:x=x const int maxn=2e5+7; int n,m; int f[maxn]; struct node{ int l,r; ll ma; }tree[maxn*4]; int a[maxn]; void push_up(int x){ tree[x].ma=max(tree[x<<1].ma,tree[x<<1|1].ma); } void built(int x,int l,int r){ tree[x]=node{l,r,-1}; if(l==r){ tree[x].ma=f[l]; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } void update(int x,int l,int r,int val){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ tree[x].ma=val; } else{ int mid=(L+R)>>1; if(mid>=l) update(x<<1,l,r,val); if(mid<r) update(x<<1|1,l,r,val); push_up(x); } } ll query(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].ma; } else{ ll ans=0; int mid=(L+R)>>1; if(mid>=l) ans=max(ans,query(x<<1,l,r)); if(mid<r) ans=max(ans,query(x<<1|1,l,r) ); return ans; } } int main() { std::ios::sync_with_stdio(false); while(cin>>n>>m){ for(int i=1;i<=n;i++){ cin>>f[i]; } built(1,1,n); char c; int x,y; while(m--){ cin>>c>>x>>y; if(c=='Q'){ cout<<query(1,x,y)<<endl; } else if(c=='U'){ update(1,x,x,y); } } } return 0; }
C.
模板,几乎没改
#include<bits/stdc++.h> #include<iostream> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x? x=y: x=x const int maxn=1e5+7; struct node{ int l,r; ll lazy,sum; void update(ll x){ sum+=x*(r-l+1); lazy+=x; } }tree[maxn*4]; void push_up(int x){ tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; } void push_down(int x){ int lazytp=tree[x].lazy; if(lazytp){ tree[x<<1].update(lazytp); tree[x<<1|1].update(lazytp); tree[x].lazy=0; } } int a[maxn]; void built(int x,int l,int r){ tree[x]=node{l,r,0,0}; if(l==r){ tree[x].sum=a[l]; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } void update(int x,int l,int r,int val){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ tree[x].update(val); } else{ push_down(x); int mid=(L+R)>>1; if(mid>=l) update(x<<1,l,r,val); if(mid<r) update(x<<1|1,l,r,val); push_up(x); } } ll query(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].sum; } else{ push_down(x); ll ans=0; int mid=(L+R)>>1; if(mid>=l) ans+=query(x<<1,l,r); if(mid<r) ans+=query(x<<1|1,l,r); push_up(x); return ans; } } int main(){ std::ios::sync_with_stdio(false); int n,q; while(cin>>n>>q){ for(int i=1;i<=n;i++){ cin>>a[i]; } built(1,1,n); while(q--){ char c; int l,r,k; cin>>c>>l>>r; if(c=='C'){ cin>>k; update(1,l,r,k); } else{ cout<<query(1,l,r)<<endl; } } } return 0; }
D.
离散化++明天一定写。。0.0
E.
建树时每个点都是1,需要修改一下懒标记,把区间加懒标记的值 变成 区间变为懒标记乘区间的值,
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x?x=y:x=x int n,q; const int maxn=1e5+7; struct node{ int l,r; ll lazy,sum; void update(ll x){ sum=x*(r-l+1); lazy=x; } }tree[maxn*4]; void push_up(int x){ tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; } void push_down(int x){ int lazytp=tree[x].lazy; if(lazytp){ tree[x<<1].update(lazytp); tree[x<<1|1].update(lazytp); tree[x].lazy=0; } } void built(int x,int l,int r){ tree[x]=node{l,r,0,0}; if(l==r){ tree[x].sum=1; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } void update(int x,int l,int r,int val){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ tree[x].update(val); } else{ push_down(x); int mid=(L+R)>>1; if(mid>=l) update(x<<1,l,r,val); if(mid<r) update(x<<1|1,l,r,val); push_up(x); } } ll query(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].sum; } else{ push_down(x); ll ans=0; int mid=(L+R)>>1; if(mid>=l) ans+=query(x<<1,l,r); if(mid<r) ans+=query(x<<1|1,l,r); push_up(x); return ans; } } int main() { std::ios::sync_with_stdio(false); int t,ca=0; cin>>t; while(t--){ ca++; cin>>n>>q; built(1,1,n); for(int i=0,x,y,z;i<q;i++){ cin>>x>>y>>z; update(1,x,y,z); } cout<<"Case "<<ca<<": The total value of the hook is "<<query(1,1,n)<<"."<<endl; } return 0; }
G.
和B的做法一样,分别保存查询最大最小值就行了,但是,好像要输入输出优化,用c++应该不会超时,于是又敲了一遍RMQ
扫描二维码关注公众号,回复:
5766838 查看本文章
线段树
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x?x=y:x=x int n,m; const int maxn=5e4+7; ll a[maxn]; struct node{ int l,r; ll maxh,minh; }tree[maxn*4]; void push_up(int x){ tree[x].maxh=max(tree[x<<1].maxh,tree[x<<1|1].maxh); tree[x].minh=min(tree[x<<1].minh,tree[x<<1|1].minh); } void built(int x,int l,int r){ tree[x]=node{l,r,-inf,inf}; if(l==r){ tree[x].minh=tree[x].maxh=a[l]; } else{ int mid=(l+r)>>1; built(x<<1 ,l ,mid ); built(x<<1|1 ,mid+1 ,r ); push_up(x); } } ll query1(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].maxh; } else{ ll ans=0; push_up(x); int mid=(L+R)>>1; if(mid>=l) ans=max(ans,query1(x<<1,l,r)); if(mid<r) ans=max(ans,query1(x<<1|1,l,r)); return ans; } } ll query2(int x,int l,int r){ int L=tree[x].l,R=tree[x].r; if(l<=L&&R<=r){ return tree[x].minh; } else{ ll ans=inf; push_up(x); int mid=(L+R)>>1; if(mid>=l) ans=min(ans,query2(x<<1,l,r)); if(mid<r) ans=min(ans,query2(x<<1|1,l,r)); return ans; } } ll query(int x,int l,int r){ return query1(x,l,r)-query2(x,l,r); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%lld",a+i); } built(1,1,n); int l,r; while(m--){ scanf("%d%d",&l,&r); printf("%lld\n",query(1,l,r) ); } return 0; }
RMQ
#include<iostream> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; #define inf 1e9+7 #define ffr(i,a,b) for(int i=a;i<b;i++) #define mem(a,b) memset( a,b,sizeof a) #define Max(x,y) y>x?x=y:x=x int n,m; const int maxn=5e4+7; ll a[maxn]; ll st1[maxn][20]; ll st2[maxn][20]={inf}; void RMQ1(){ for(int j=1;j<=20;j++){ for(int i=1;i<=n;i++){ if(i+(1<<j)-1<=n){ st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1)) ][j-1]); } } } } void RMQ2(){ for(int j=1;j<=20;j++){ for(int i=1;i<=n;i++){ if(i+(1<<j)-1<=n){ st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1)) ][j-1]); } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%lld",a+i); st1[i][0]=st2[i][0]=a[i]; } RMQ1(); RMQ2(); while(m--){ int l,r; scanf("%d%d",&l,&r); int k=log2(r-l+1); ll a=max( st1[l][k],st1[r-(1<<k)+1][k] ); ll b=min( st2[l][k],st2[r-(1<<k)+1][k] ); printf("%lld\n", a-b ); } return 0; }