线段树板子

本文档介绍了四种不同场景下的树状数组实现,包括线段树1(区间加、区间查询)、树状数组1(单点修改、区间求和)、树状数组2(区间加、单点查询),以及区间最大值最小值查询。通过实例展示了如何运用树状数组进行高效的数据结构操作。
摘要由CSDN通过智能技术生成

一、建树、区间加、区间查询和

P3372 【模板】线段树 1

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], opt, x, y, k;
struct SegmentTree
{
	int l, r;
	long long sum, lazy;	
}t[400010];
//建树 build(1, 1, n); 
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].sum=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void spread(int p)
{
	if(t[p].lazy){
		t[p*2].sum+=t[p].lazy*(t[p*2].r-t[p*2].l+1);
		t[p*2+1].sum+=t[p].lazy*(t[p*2+1].r-t[p*2+1].l+1);
		t[p*2].lazy+=t[p].lazy;
		t[p*2+1].lazy+=t[p].lazy;
		t[p].lazy=0;
	}	
} 
void change(int p, int l, int r, int d)
{
	if(l<=t[p].l && r>=t[p].r){
		t[p].sum+=d*(t[p].r-t[p].l+1);
		t[p].lazy+=d;
		return;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid){
		change(p*2, l, r, d);
	}
	if(r>mid){
		change(p*2+1, l, r, d);
	}
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//区间查询  asd(1, l, r);
long long ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){		//完全覆盖 
		return t[p].sum; 
	}
	spread(p);						//下传延迟标记 
	int mid=(t[p].l+t[p].r)/2;
	long long ans=0;
	if(l<=mid){		//和左子节点有重叠 
		ans+=ask(p*2, l, r);
	}
	if(r>mid){		//和右子节点有重叠 
		ans+=ask(p*2+1, l, r);
	} 
	return ans;
} 
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		scanf("%d", &a[i]);
	}
	build(1, 1, n);
	while(m--){
		scanf("%d", &opt);
		if(opt==1){
			scanf("%d %d %d", &x, &y, &k);
			change(1, x, y, k);
		}
		else if(opt==2){
			scanf("%d %d", &x, &y);
			printf("%lld\n", ask(1, x, y));
		}
	}
	return 0;
}

二、建树、单点修改、区间求和(不需要lazy tag)

P3374 【模板】树状数组 1

#include <bits/stdc++.h>
using namespace std;
int n, m, a[500010], opt;
struct SegmentTree
{
	int l, r;
	long long sum;
}t[2000010];
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].sum=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void change(int p, int x, int v)
{
	if(t[p].l==t[p].r){
		t[p].sum+=v;
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(x<=mid){
		change(p*2, x, v);
	}
	else{
		change(p*2+1, x, v);
	}
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
long long ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].sum;
	}
	int mid=(t[p].l+t[p].r)>>1;
	long long ans=0;
	if(l<=mid){
		ans+=ask(p*2, l, r);
	}
	if(r>mid){
		ans+=ask(p*2+1, l, r);
	}
	return ans;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		scanf("%d", &a[i]);
	}
	build(1, 1, n);
	while(m--){
		int x, y, k;
		scanf("%d", &opt);
		if(opt==1){
			scanf("%d %d", &x, &k);
			change(1, x, k);
		}
		else if(opt==2){
			scanf("%d %d", &x, &y);
			printf("%lld\n", ask(1, x, y));
		}
	}
	return 0;
}

三、建树、区间加、单点查询

P3368 【模板】树状数组 2

#include <bits/stdc++.h>
using namespace std;
int n, m, a[500010], x, y, k, opt;
struct SegmentTree
{
	int l, r;
	long long sum, lazy;	
}t[2000010];
//建树 build(1, 1, n); 
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].sum=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void spread(int p)
{
	if(t[p].lazy){
		t[p*2].sum+=t[p].lazy*(t[p*2].r-t[p*2].l+1);
		t[p*2+1].sum+=t[p].lazy*(t[p*2+1].r-t[p*2+1].l+1);
		t[p*2].lazy+=t[p].lazy;
		t[p*2+1].lazy+=t[p].lazy;
		t[p].lazy=0;
	}	
} 
void change(int p, int l, int r, int d)
{
	if(l<=t[p].l && r>=t[p].r){
		t[p].sum+=d*(t[p].r-t[p].l+1);
		t[p].lazy+=d;
		return;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid){
		change(p*2, l, r, d);
	}
	if(r>mid){
		change(p*2+1, l, r, d);
	}
	t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//区间查询  asd(1, l, r);
long long ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){		//完全覆盖 
		return t[p].sum; 
	}
	spread(p);						//下传延迟标记 
	int mid=(t[p].l+t[p].r)/2;
	long long ans=0;
	if(l<=mid){		//和左子节点有重叠 
		ans+=ask(p*2, l, r);
	}
	if(r>mid){		//和右子节点有重叠 
		ans+=ask(p*2+1, l, r);
	} 
	return ans;
} 
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		scanf("%d", &a[i]);
	}
	build(1, 1, n);
	while(m--){
		scanf("%d", &opt);
		if(opt==1){
			scanf("%d %d %d", &x, &y, &k);
			change(1, x, y, k);
		}
		else if(opt==2){
			scanf("%d", &x);
			printf("%lld\n", ask(1, x, x));
		}
	}
	return 0;
}

四、建树、区间最大值、最小值查询

P2880 [USACO07JAN] Balanced Lineup G

#include <bits/stdc++.h>
using namespace std;
int n, q, a, b, h[50010];
struct SegmentTree{
	int l, r, mx, mn;
}t[200010];
//建树 
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].mx=t[p].mn=h[l];
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	build(p<<1, l, mid);
	build(p<<1|1, mid+1, r);
	t[p].mx=max(t[p<<1].mx, t[p<<1|1].mx);
	t[p].mn=min(t[p<<1].mn, t[p<<1|1].mn);
}
//查询区间最大值 
int ask1(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].mx;
	}
	int mid=(t[p].l+t[p].r)>>1;
	int maxans=0;
	if(l<=mid){
		maxans=max(maxans, ask1(p<<1, l, r));	//ask的时候一定是l到r的 
	}
	if(r>mid){
		maxans=max(maxans, ask1(p<<1|1, l, r));	//ask的时候一定是l到r的
	}
	return maxans;
}
//查询区间最小值 
int ask2(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].mn;
	}
	int mid=(t[p].l+t[p].r)>>1;
	int minans=1e7;
	if(l<=mid){
		minans=min(minans, ask2(p<<1, l, r));	//ask的时候一定是l到r的
	}
	if(r>mid){
		minans=min(minans, ask2(p<<1|1, l, r));	//ask的时候一定是l到r的
	}
	return minans;
}
int main()
{
	scanf("%d %d", &n, &q);
	for(int i=1; i<=n; ++i){
		scanf("%d", &h[i]);
	}
	build(1, 1, n);
	while(q--){
		scanf("%d %d", &a, &b);
		printf("%d\n", ask1(1, a, b)-ask2(1, a, b));
	}
	return 0;
}

P3865 【模板】ST 表

不加快读会有一个点超时

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], li, ri;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
struct SegmentTree{
	int l, r, mx;
}t[400010];
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].mx=a[l];
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	build(p<<1, l, mid);
	build(p<<1|1, mid+1, r);
	t[p].mx=max(t[p<<1].mx, t[p<<1|1].mx);
}
int ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].mx;
	}
	int value=0;
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid){
		value=max(value, ask(p<<1, l, r));
	}
	if(r>mid){
		value=max(value, ask(p<<1|1, l, r));
	}
	return value;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		a[i]=read();
	}
	build(1, 1, n);
	while(m--){
		li=read();
		ri=read();
		printf("%d\n", ask(1, li, ri));
	}
	return 0;
} 

P2251 质量检测

区间最小值

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010];
struct SegmentTree
{
	int l, r, mn;	
}t[400010];
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].mn=a[l];
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	build(p<<1, l, mid);
	build(p<<1|1, mid+1, r);
	t[p].mn=min(t[p<<1].mn, t[p<<1|1].mn);
}
int ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].mn;
	}
	int value=10000000;
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid){
		value=min(value, ask(p<<1, l, r));
	}
	if(r>mid){
		value=min(value, ask(p<<1|1, l, r));
	}
	return value;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		scanf("%d", &a[i]);
	}
	build(1, 1, n);	
	for(int i=1; i<=n-m+1; ++i){
		printf("%d\n", ask(1, i, i+m-1));
	}
	return 0;
}

五、区间异或

P2574 XOR的艺术

#include <bits/stdc++.h>
using namespace std;
int n, m, op, l, r, a[200010];
struct SegmentTree
{
	int l, r, lazy, sum;
}t[800010];
void build(int p, int l, int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].sum=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(p<<1, l, mid);
	build(p<<1|1, mid+1, r);
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
void spread(int p)
{
	if(t[p].lazy){
		if(t[p].lazy%2){
			t[p<<1].sum=(t[p<<1].r-t[p<<1].l+1)-t[p<<1].sum;
			t[p<<1|1].sum=(t[p<<1|1].r-t[p<<1|1].l+1)-t[p<<1|1].sum; 
		} 
		t[p<<1].lazy+=t[p].lazy;
		t[p<<1|1].lazy+=t[p].lazy;
		t[p].lazy=0;
	}
}
void change(int p, int l, int r, int d)
{
	if(l<=t[p].l && r>=t[p].r){
		t[p].sum=(t[p].r-t[p].l+1)-t[p].sum;
		t[p].lazy+=d;
		return;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid){
		change(p<<1, l, r, d);		//注意是l和r 
	}
	if(r>mid){
		change(p<<1|1, l, r, d);	//注意是l和r
	}
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
int ask(int p, int l, int r)
{
	if(l<=t[p].l && r>=t[p].r){
		return t[p].sum;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)>>1;
	int ans=0;
	if(l<=mid){
		ans+=ask(p<<1, l, r);
	}
	if(r>mid){
		ans+=ask(p<<1|1, l, r);
	}
	return ans;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		scanf("%1d", &a[i]);
	}
	build(1, 1, n);
	while(m--){
		scanf("%d %d %d", &op, &l, &r);
		//将伤害串的 [l,r]区间内的0变成1, 1变成0
		if(op==0){	//异或1相当于取反 
			change(1, l, r, 1); 
		}
		else if(op==1){	//询问伤害串的 [l,r]区间内有多少个字符1
			printf("%d\n", ask(1, l, r));
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值