刍议线段树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.\) \(L \leq t_p.l \leq t_p.r \leq R\) 查询区间完全包括此区间,return;
\(2.\) \(L \le mid\) 递归左区间
\(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 @ 2024-08-09 16:33  Qian·JXのjoker  阅读(12)  评论(1编辑  收藏  举报