刍议线段树1 (单点修改,区间查询)

线段树

形状类似一颗二叉树
三个步骤:
1.建树
2.修改
3.查询

以求区间最大值为例(不带延迟标记--单点修改,区间查询)

建树

定义一个数据类型,里面存上l,r,dat,即左儿子,右儿子和区间内最大值

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);

区间查询

三种情况讨论:
1. Ltp.ltp.rR 查询区间完全包括此区间,return;
2. Lmid 递归左区间
3. R>mid 递归右区间

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;
}
posted @   Qian·JXのjoker  阅读(27)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示