【高级数据结构】线段树

目录

树状数组1(单点修改,区间查询)

树状数组2(区间修改,单点查询)

线段树1(区间修改,区间查询)

代码源线段树1(查询最小值出现次数)

 代码源线段树2(最大字段和)

动态开点


树状数组1(单点修改,区间查询)

题目链接:  https://www.luogu.com.cn/problem/P3374

代码:

// Problem: P3374 【模板】树状数组 1
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3374
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 5e5+5;

int n,q;
int a[N];

struct node{
	ll t,val,sz,l,r;
}seg[N*4];


void update(int id){
	seg[id].val=seg[id*2].val+seg[id*2+1].val;
}

void settag(int id,ll t){
	seg[id].t=seg[id].t+t;
	seg[id].val=seg[id].val+seg[id].sz*t;
}

void pushdown(int id){
	if(seg[id].t!=0){  
		settag(id*2,seg[id].t);
		settag(id*2+1,seg[id].t);
		seg[id].t=0;
	}
}

void build(int id,int l,int r){
	seg[id].sz=r-l+1;
	if(l==r){
		seg[id].val={a[l]};
	}
	else{
		int mid=(l+r)/2;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		update(id);
	}
}

void change(int id,int l,int r,int pos,ll val){
	if(l==r){
		seg[id].val=seg[id].val+val;
		return;
	}
	int mid=(l+r)/2;
	if(pos<=mid){
		change(id*2,l,mid,pos,val);
	}
	else if(pos>mid){
		change(id*2+1,mid+1,r,pos,val);
	}
	update(id);
}

ll query(int id,int l,int r,int ql,int qr){
	if(ql==l&&qr==r){
		return seg[id].val;
	}
	int mid=(l+r)/2;
	pushdown(id);
	if(qr<=mid){
		return query(id*2,l,mid,ql,qr);
	}
	else if(ql>mid){
		return query(id*2+1,mid+1,r,ql,qr);
	}
	else{
		return query(id*2,l,mid,ql,mid)+query(id*2+1,mid+1,r,mid+1,qr);
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=0;i<q;i++){
		int ty;
		cin>>ty;
		if(ty==1){
			int x,d;
			cin>>x>>d;
			change(1,1,n,x,d);
		}
		else{
			int l,r;
			cin>>l>>r;
			cout<<query(1,1,n,l,r)<<"\n";
		}
	}

	
	return 0;	

}

树状数组2(区间修改,单点查询)

 题目链接:  https://www.luogu.com.cn/problem/P3368

代码:

// Problem: P3372 【模板】线段树 1
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3372
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 5e5+5;

int n,q;
int a[N];

struct node{
	ll t,val,sz,l,r;
}seg[N*4];


void update(int id){
	seg[id].val=seg[id*2].val+seg[id*2+1].val;
}

void settag(int id,ll t){
	seg[id].t=seg[id].t+t;
	seg[id].val=seg[id].val+seg[id].sz*t;
}

void pushdown(int id){
	if(seg[id].t!=0){  
		settag(id*2,seg[id].t);
		settag(id*2+1,seg[id].t);
		seg[id].t=0;
	}
}

void build(int id,int l,int r){
	seg[id].sz=r-l+1;
	if(l==r){
		seg[id].val={a[l]};
	}
	else{
		int mid=(l+r)/2;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		update(id);
	}
}

void modify(int id,int l,int r,int ql,int qr,ll t){
	if(l==ql&&r==qr){
		settag(id,t);
		return;
	}
	int mid=(l+r)/2;
	pushdown(id);
	if(qr<=mid){
		modify(id*2,l,mid,ql,qr,t);
	}
	else if(ql>mid){
		modify(id*2+1,mid+1,r,ql,qr,t);
	}
	else{
		modify(id*2,l,mid,ql,mid,t);
		modify(id*2+1,mid+1,r,mid+1,qr,t);
	}
	update(id);
}

ll query(int id,int l,int r,int pos){
	if(r==l){
		return seg[id].val;
	}
	int mid=(l+r)/2;
	pushdown(id);
	if(pos<=mid){
		return query(id*2,l,mid,pos);
	}
	else if(pos>mid){
		return query(id*2+1,mid+1,r,pos);
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=0;i<q;i++){
		int ty;
		cin>>ty;
		if(ty==1){
			int l,r,d;
			cin>>l>>r>>d;
			modify(1,1,n,l,r,d);
		}
		else{
			int x;
			cin>>x;
			cout<<query(1,1,n,x)<<"\n";
		}
	}

	
	return 0;	

}

线段树1(区间修改,区间查询)

题目链接:  https://www.luogu.com.cn/problem/P3372

代码:

// Problem: P3372 【模板】线段树 1
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3372
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2e5+5;

int n,q;
int a[N];

struct node{
	ll t,val,sz;
}seg[N*4];


void update(int id){
	seg[id].val=seg[id*2].val+seg[id*2+1].val;
}

void settag(int id,ll t){
	seg[id].t=seg[id].t+t;
	seg[id].val=seg[id].val+seg[id].sz*t;
}

void pushdown(int id){
	if(seg[id].t!=0){  
		settag(id*2,seg[id].t);
		settag(id*2+1,seg[id].t);
		seg[id].t=0;
	}
}

void build(int id,int l,int r){
	seg[id].sz=r-l+1;
	if(l==r){
		seg[id].val={a[l]};
	}
	else{
		int mid=(l+r)/2;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		update(id);
	}
}

void modify(int id,int l,int r,int ql,int qr,ll t){
	if(l==ql&&r==qr){
		settag(id,t);
		return;
	}
	int mid=(l+r)/2;
	pushdown(id);
	if(qr<=mid){
		modify(id*2,l,mid,ql,qr,t);
	}
	else if(ql>mid){
		modify(id*2+1,mid+1,r,ql,qr,t);
	}
	else{
		modify(id*2,l,mid,ql,mid,t);
		modify(id*2+1,mid+1,r,mid+1,qr,t);
	}
	update(id);
}

ll query(int id,int l,int r,int ql,int qr){
	if(l==ql&&r==qr){
		return seg[id].val;
	}
	int mid=(l+r)/2;
	pushdown(id);
	if(qr<=mid){
		return query(id*2,l,mid,ql,qr);
	}
	else if(ql>mid){
		return query(id*2+1,mid+1,r,ql,qr);
	}
	else{
		return query(id*2,l,mid,ql,mid)+query(id*2+1,mid+1,r,mid+1,qr);
	}
}

int main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=0;i<q;i++){
		int ty;
		cin>>ty;
		if(ty==1){
			int l,r,d;
			cin>>l>>r>>d;
			modify(1,1,n,l,r,d);
		}
		else{
			int l,r;
			cin>>l>>r;
			cout<<query(1,1,n,l,r)<<"\n";
		}
	}

	
	return 0;	

}

代码源线段树1(查询最小值出现次数)

题目链接:  http://oj.daimayuan.top/course/15/problem/654

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2e5+5;
const int inf = 0x3f3f3f3f;

int n,q;
int a[N];

struct info{
	
};

info operator +(const info &l,const info &r){
	info a;
	a.minv=min(l.minv,r.minv);
	if(l.minv==r.minv){
		a.mincnt=l.mincnt+r.mincnt;
	}
	else if(l.minv<r.minv){
		a.mincnt=l.mincnt;
	}
	else{
		a.mincnt=r.mincnt;
	}
	return a;
}

struct node{
	info val;
}seg[N*4];

void update(int id){
	seg[id].val=seg[id*2].val+seg[id*2+1].val;
}

void build(int id,int l,int r){
	if(l==r){
		seg[id].val={a[l],1};
	}
	else{
		int mid=(l+r)/2;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		update(id);
	}
}

void change(int id,int l,int r,int pos,int val){
	if(l==r){
		seg[id].val={val,1};
		//a[pos]=val;
	}
	else{
		int mid=(l+r)/2;
		if(pos<=mid){
			change(id*2,l,mid,pos,val);
		}
		else{
			change(id*2+1,mid+1,r,pos,val);
		}
		update(id);
	}
}

info query(int id,int l,int r,int ql,int qr){
	if(l==ql&&r==qr){
		return seg[id].val;
	}
	int mid=(l+r)/2;
	if(qr<=mid){
		return query(id*2,l,mid,ql,qr);
	}
	else if(ql>mid){
		return query(id*2+1,mid+1,r,ql,qr);
	}
	else{
		return query(id*2,l,mid,ql,mid)+query(id*2+1,mid+1,r,mid+1,qr);
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=0;i<q;i++){
		int ty;
		cin>>ty;
		if(ty==1){
			int x,d;
			cin>>x>>d;
			change(1,1,n,x,d);
		}
		else{
			int l,r;
			cin>>l>>r;
			auto ans=query(1,1,n,l,r);
			cout<<ans.minv<<' '<<ans.mincnt<<"\n";
		}
	}
	
	
	
	return 0;	

}

 代码源线段树2(最大字段和)

题目链接: 

目录

树状数组1(单点修改,区间查询)

树状数组2(区间修改,单点查询)

线段树1(区间修改,区间查询)

代码源线段树1(查询最小值出现次数)

 代码源线段树2(最大字段和)


代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2e5+5;
const int inf = 0x3f3f3f3f;

int n,q;
int a[N];

struct info{
	ll mss,mpre,msuf,s;
	info(){}
	info(int a):mss(a),mpre(a),msuf(a),s(a){}
};

info operator +(const info &l,const info &r){
	info a;
	a.mss=max({l.mss,r.mss,l.msuf+r.mpre});
	a.mpre=max(l.mpre,l.s+r.mpre);
	a.msuf=max(r.msuf,r.s+l.msuf);
	a.s=l.s+r.s;
	return a;
}

struct node{
	info val;
}seg[N*4];

void update(int id){
	seg[id].val=seg[id*2].val+seg[id*2+1].val;
}

void build(int id,int l,int r){
	if(l==r){
		seg[id].val=info(a[l]);
	}
	else{
		int mid=(l+r)/2;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		update(id);
	}
}

void change(int id,int l,int r,int pos,int val){
	if(l==r){
		seg[id].val=info(val);
		//a[pos]=val;
	}
	else{
		int mid=(l+r)/2;
		if(pos<=mid){
			change(id*2,l,mid,pos,val);
		}
		else{
			change(id*2+1,mid+1,r,pos,val);
		}
		update(id);
	}
}

info query(int id,int l,int r,int ql,int qr){
	if(l==ql&&r==qr){
		return seg[id].val;
	}
	int mid=(l+r)/2;
	if(qr<=mid){
		return query(id*2,l,mid,ql,qr);
	}
	else if(ql>mid){
		return query(id*2+1,mid+1,r,ql,qr);
	}
	else{
		return query(id*2,l,mid,ql,mid)+query(id*2+1,mid+1,r,mid+1,qr);
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=0;i<q;i++){
		int ty;
		cin>>ty;
		if(ty==1){
			int x,d;
			cin>>x>>d;
			change(1,1,n,x,d);
		}
		else{
			int l,r;
			cin>>l>>r;
			auto ans=query(1,1,n,l,r);
			cout<<ans.mss<<"\n";
		}
	}
	
	
	
	return 0;	

}

动态开点

https://www.luogu.com.cn/problem/P2781

#include<cstdio>//动态开点线段树是一类特殊的线段树,与普通的线段树不同的是,每一个节点的左右儿子不是该点编号的两倍和两倍加一,而是现加出来的
#include<iostream>//https://blog.csdn.net/u012972031/article/details/88751811 https://www.cnblogs.com/szbszb/p/11243728.html
#include<cstring>

#define int long long

using namespace std;
const int N=1e7+10;
struct node {
	int ls,rs,lazy;//左儿子地址,右儿子地址,延迟标记
	long long sum;//区间和
} tr[N*4];
int root=0,cnt=0;//根据insert代码(11行),root从1开始
void init() {
	memset(tr,0,sizeof(tr));
	root=0,cnt=0;
}
void insert(int &root,int l,int r,int ll,int rr,int x) { //建树&&区间修改 root区间范围[l,r],修改范围[ll,rr],修改增量x root是人为规定的编号,涉及修改,传引用 
	if(!root)root=++cnt;//root还没开,开点
	int len=min(r,rr)-max(l,ll)+1;//b为修改区间在当前区间的长度 例如真子集[1,N],修改[10,20],b=20-10+1=11 或者交集[50,100],修改[30,70],b=70-50+1 =21
	if(len<0)	return;//或者空集[50,100]修改[10,20] b=20-50+1 =-29 <0
	tr[root].sum+=len*x;
	if(l>=ll&&r<=rr) { //真子集
		tr[root].lazy+=x;
		return;
	}
	int mid=l+r>>1;
	if(ll<=mid)insert(tr[root].ls,l,mid,ll,rr,x);
	if(rr>mid)insert(tr[root].rs,mid+1,r,ll,rr,x);
}
int query(int root,int l,int r,int ll,int rr) {//区间查询,在范围为[l,r]的root中查询[ll,rr]的区间和
	if(l>=ll&&r<=rr)return tr[root].sum;//真子集
	int mid=l+r>>1;
	if(tr[root].lazy) {//下放延迟标记
		if(!tr[root].ls)	tr[root].ls=++cnt;
		tr[tr[root].ls].lazy+=tr[root].lazy;
		tr[tr[root].ls].sum+=tr[root].lazy*(mid-l+1);
		if(!tr[root].rs)	tr[root].rs=++cnt;
		tr[tr[root].rs].lazy+=tr[root].lazy;
		tr[tr[root].rs].sum+=tr[root].lazy*(r-mid);
		tr[root].lazy=0;
	}
	long long ans=0;
	if(ll<=mid)	ans+=query(tr[root].ls,l,mid,ll,rr);
	if(rr>mid)	ans+=query(tr[root].rs,mid+1,r,ll,rr);
	return ans;
}
signed main() {
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	// for(int i=1; i<=n; i++) {
		// int temp;
		// cin>>temp;
		// insert(root,1,n,i,i,temp);
	// }
	for(int i=1; i<=m; i++) {
		int ta,tb,tc,td;
		cin>>ta>>tb>>tc;
		if(ta==1) {
			cin>>td;
			insert(root,1,n,tb,tc,td);
		} else if(ta==2) {
			cout<<query(root,1,n,tb,tc)<<endl;
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值