刍议线段树1 (单点修改,区间查询)
线段树
形状类似一颗二叉树
三个步骤:
以求区间最大值为例(不带延迟标记--单点修改,区间查询)
建树
定义一个数据类型,里面存上
struct node{ int l,r,dat; }t[1<<N];//注意,建树要开4倍空间,下标是编号,而非位置 void build(int p,int l,int r){ t[p].l=l;t[p].r=r; if(l==r){ t[p].dat=a[l]; return ; } int mid=(l+r)>>1; build(2*p,l,mid);//left buile(2*p+1,mid+1,r);//right t[p].dat=max(t[2*p].dat,t[2*p+1].dat); } build(1,1,n);//调用入口
单点修改
void change(int p,int x,int v){ int l=t[p].l;int r=t[p].r; if(l==r) { t[l].dat=v; return ; } int mid=(l+r)>>1; if(x<=mid) change(2*p,x,v);//这里后两个参数是传x,v,不要搞错了(因为我就搞错了) else change(x*p+1,x,v); t[p].dat=max(t[2*p].dat,t[2*p+1].dat); } change(1,x,v);
区间查询
三种情况讨论:
int ask(int p,int L,int R){ int l=t[p].l,r=t[p].r; if(L<=l&&r<=R) return t[p].dat; int mid=(l+r)>>1; int val=-0x3f3f3f3f; if(L<=mid) val=max(ask(2*p,L,R),val);//左子树更新 if(R>mid) val=max(ask(2*p+1,L,R),val);//右子树更新 return val; } ask(1,L,R);
完整代码:
#include<bits/stdc++.h> using namespace std; #define int long long const int N=1e5+5; struct node{ int l,r,dat; }t[4*N]; int n,m; int a[4*N]; #define ls 2*p #define rs 2*p+1 void build(int p,int l,int r){ t[p].l=l; t[p].r=r; if(l==r){ t[p].dat=a[l]; return ; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); t[p].dat=max(t[ls].dat,t[rs].dat); } void change(int p,int x,int v){ int l=t[p].l; int r=t[p].r; if(l==r){ t[p].dat=v; return; } int mid=(l+r)>>1; if(x<=mid) change(ls,x,v); else change(rs,x,v); t[p].dat=max(t[ls].dat,t[rs].dat); } int query(int p,int L,int R){ int l=t[p].l; int r=t[p].r; if(L<=l&&r<=R) return t[p].dat; int val=-0x3f3f3f3f; int mid=(l+r)>>1; if(L<=mid) val=max(val,query(ls,L,R));//注意是查询边界与mid比较 if(R>mid) val=max(val,query(rs,L,R)); return val; } signed main(){ //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); while(m--){ char opt; int x,y; cin>>opt>>x>>y; if(opt=='U'){ change(1,x,y); } else{ cout<<query(1,x,y)<<endl; } } return 0; }
作业:
T1:
入口1:
https://www.acwing.com/problem/content/description/246/
入口2:
https://www.luogu.com.cn/problem/SP1716
T2:
入口1:
https://www.acwing.com/problem/content/description/247/
入口2:
https://www.luogu.com.cn/problem/P10463
要认真思考,不要自欺欺人,结果不会陪你演戏。
……
算了,我心软,放出作业的代码供大家参考。
T1
#include<bits/stdc++.h> using namespace std; #define int long long #define FOR(i,_l,_r) for(int i=_l;i<=_r;i++) #define ls (p<<1) #define rs (p<<1|1) #define L al[p] #define R ar[p] #define mid ((L+R)>>1) const int N=500000+5; struct node{ int s,lx,rx,dat; }t[N<<2]; int al[N<<2],ar[N<<2]; int n,m; int a[N]; node merge(node a,node b){ node tr; tr.s=a.s+b.s; tr.lx=max(a.lx,a.s+b.lx); tr.rx=max(b.rx,b.s+a.rx); tr.dat=max( max(a.dat,b.dat) , a.rx+b.lx); return tr; } void up(int p){ t[p]=merge(t[ls],t[rs]); } void build(int p,int l,int r){ L=l;R=r; if(l==r){ t[p].dat=t[p].lx=t[p].rx=t[p].s=a[l]; return ; } build(ls,l,mid); build(rs,mid+1,r); up(p); } void change(int p,int x,int v){ if(L==R){ t[p].dat=t[p].lx=t[p].rx=t[p].s=v; return ; } if(x<=mid) change(ls,x,v); else change(rs,x,v); up(p); } node query(int p,int l,int r){ if(l<=L&&R<=r) return t[p]; if(r<=mid) return query(ls,l,r); else if(l>mid) return query(rs,l,r); return merge(query(ls,l,r),query(rs,l,r)); } signed main(){ // freopen("test.in","r",stdin); // freopen("test.out","w",stdout); ios::sync_with_stdio(false); cin.tie(NULL); cin>>n>>m; FOR(i,1,n) cin>>a[i]; build(1,1,n); while(m--){ int opt,x,y; cin>>opt>>x>>y; if(opt==1){ if(x>y) swap(x,y); cout<<query(1,x,y).dat<<endl; } else change(1,x,y); } return 0; }
T2
#include<bits/stdc++.h> using namespace std; #define int long long #define ls (p<<1) #define rs (p<<1|1) #define mid ((l+r)>>1) #define FOR(i,_l,_r) for(int i=_l;i<=_r;i++) const int N=500000+5; int n,m; int a[N],b[N],c[N];//a-原数组,b-gcd差分数组,c-a的差分数组 struct node{ int l,r,ans; }t[N<<2]; int gcd(int x,int y){ return __gcd(x,y); } void up(int p){ t[p].ans=gcd(t[ls].ans,t[rs].ans); } void build(int p,int l,int r){ t[p].l=l;t[p].r=r; if(l==r){ t[p].ans=b[l]; return; } build(ls,l,mid); build(rs,mid+1,r); up(p); } void change(int p,int x,int v){ int l=t[p].l; int r=t[p].r; if(l==r){ t[p].ans+=v; return; } if(x>mid) change(rs,x,v); else change(ls,x,v); up(p); } int query_b(int p,int L,int R){ int l=t[p].l; int r=t[p].r; if(L<=l&&r<=R){ return t[p].ans; } int ans=0; if(R>mid) ans=gcd(ans,query_b(rs,L,R)); if(L<=mid) ans=gcd(ans,query_b(ls,L,R)); return abs(ans); } int lowbit(int x){ return x&-x; } void add(int x,int k){ while(x<=n){ c[x]+=k; x+=lowbit(x); } } int query_c(int x){ int ans=0; while(x){ ans+=c[x]; x-=lowbit(x); } return ans; } signed main(){ // freopen("test.in","r",stdin); // freopen("test.out","w",stdout); ios::sync_with_stdio(false); cin.tie(NULL);cout.tie(NULL); cin>>n>>m; FOR(i,1,n){ cin>>a[i]; b[i]=a[i]-a[i-1]; } build(1,1,n); while(m--){ char opt; cin>>opt; if(opt=='Q'){ int l,r; cin>>l>>r; cout<<gcd(a[l]+query_c(l),query_b(1,l+1,r))<<endl; } else{ int l,r,v; cin>>l>>r>>v; change(1,l,v); add(l,v); if(r+1<=n){ change(1,r+1,-v); add(r+1,-v); } } } return 0; }