代码源 线段树模板

线段树1

 

思路:

我们需要维护的东西是序列的最小值和最小值个数

这道题没有修改操作,因此不考虑修改

然后考虑Pushup

最小值很简单,直接取min

最小值个数怎么维护呢?考虑这个区间需要维护的值如何从左右两个区间获得

如果左右两个子区间的最小值相同,那么就可以直接相加

否则,如果这个区间的最小值是左区间最小值,直接赋值左区间的

否则就是右区间的

学一学dls的代码风格,感觉很高级QwQ

Code:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int mxn=2e5+10;
const int mxe=2e5+10;

struct info{
	int minv,mincnt;
};

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 ty{
	info val;
}tree[mxe<<2];

int n,Q,x,d,l,r,op;
int a[mxn]; 

void pushup(int rt){
	tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
}
void build(int rt,int l,int r){
	if(l==r){
		tree[rt].val={a[l],1};
		return;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
info query(int rt,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		return tree[rt].val;
	}
	int mid=l+r>>1;
	if(y<=mid) return query(rt<<1,l,mid,x,y);
	else if(x>mid) return query(rt<<1|1,mid+1,r,x,y);
	else{
		return query(rt<<1,l,mid,x,y)+query(rt<<1|1,mid+1,r,x,y);
	}
}
void change(int rt,int l,int r,int x,int k){
	if(l==r){
		tree[rt].val={k,1};
		return;
	}
	int mid=l+r>>1;
	if(x<=mid) change(rt<<1,l,mid,x,k);
	else change(rt<<1|1,mid+1,r,x,k);
	pushup(rt);
}
void solve(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(Q--){
		cin>>op;
		if(op==1){
			cin>>x>>d;
			change(1,1,n,x,d);
		}else{
			cin>>l>>r;
			cout<<query(1,1,n,l,r).minv<<" "<<query(1,1,n,l,r).mincnt<<'\n';
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int __=1;//cin>>__;
	while(__--)solve();return 0;
}

线段树2

题意:

 

思路:

我们需要维护一个区间的最大子段和

两个子区间的最大子段和怎么得到一整个区间的最大子段和呢

分类讨论即可

这个子段可能完全出现在左区间,也可能完全出现在右区间,也可能是左区间的右部分+右区间的左部分

前两种情况直接赋值即可

对于第三种情况,其实就是左区间的右部分最大子段和+右区间的左部分的最大子段和 之和

因此我们需要维护这两个值

然后开始考虑怎么维护

对于左部分最大子段和,它可能是左区间的左部分最大子段和,也有可能是左区间一整个区间+右区间的左部分最大子段和

右部分最大子段和同理

最后来看dls的板子,它需要写构造函数,因为我们这次在build的时候没有把所有的值都初始化

Code:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int mxn=2e5+10;
const int mxe=2e5+10;

struct info{
	int 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.s=l.s+r.s;
	a.mss=max(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);
	return a;
}

struct ty{
	info val;
}tree[mxe<<2];

int n,Q,x,d,l,r,op;
int a[mxn]; 

void pushup(int rt){
	tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
}
void build(int rt,int l,int r){
	if(l==r){
		tree[rt].val=info(a[l]);
		return;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
info query(int rt,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		return tree[rt].val;
	}
	int mid=l+r>>1;
	if(y<=mid) return query(rt<<1,l,mid,x,y);
	else if(x>mid) return query(rt<<1|1,mid+1,r,x,y);
	else{
		return query(rt<<1,l,mid,x,y)+query(rt<<1|1,mid+1,r,x,y);
	}
}
void change(int rt,int l,int r,int x,int k){
	if(l==r){
		tree[rt].val=info(k);
		return;
	}
	int mid=l+r>>1;
	if(x<=mid) change(rt<<1,l,mid,x,k);
	else change(rt<<1|1,mid+1,r,x,k);
	pushup(rt);
}
void solve(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(Q--){
		cin>>op;
		if(op==1){
			cin>>x>>d;
			change(1,1,n,x,d);
		}else{
			cin>>l>>r;
			cout<<query(1,1,n,l,r).mss<<'\n';
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int __=1;//cin>>__;
	while(__--)solve();return 0;
}

线段树打标记

题意:

思路:

我们需要维护的是最大值,这个很好维护,Pushup直接取max即可

问题是需要区间修改,区间加

这个加个add标记即可,在Pushdown的时候更新mx属性

这种打标记的最重要的是如何在Pushdown的时候观察区间修改操作如何影响需要维护的值 

在这里很简单,直接最大值mx使加上add即可

Code:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int mxn=2e5+10;
const int mxe=2e5+10;

struct Segtree{
	int mx,add;
}tree[mxe<<2];

int n,Q,x,d,l,r,op;
int a[mxn]; 

void settag(int rt,int t){
	tree[rt].add+=t;
	tree[rt].mx+=t;
}
void pushup(int rt){
	tree[rt].mx=max(tree[rt<<1].mx,tree[rt<<1|1].mx);
}
void pushdown(int rt){
	if(tree[rt].add){
		settag(rt<<1,tree[rt].add);
		settag(rt<<1|1,tree[rt].add);
		tree[rt].add=0;
	}
}
void build(int rt,int l,int r){
	if(l==r){
		tree[rt]={a[l],0};
		return;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
int query(int rt,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr){
		return tree[rt].mx;
	}
	pushdown(rt);
	int mid=l+r>>1;
	if(qr<=mid) return query(rt<<1,l,mid,ql,qr);
	else if(ql>mid) return query(rt<<1|1,mid+1,r,ql,qr);
	else{
		return max(query(rt<<1,l,mid,ql,qr),query(rt<<1|1,mid+1,r,ql,qr));
	}
}
void modify(int rt,int l,int r,int ql,int qr,int d){
	if(ql<=l&&r<=qr){
		settag(rt,d);
		return;
	}
	pushdown(rt);
	int mid=l+r>>1;
	if(qr<=mid) modify(rt<<1,l,mid,ql,qr,d);
	else if(ql>mid) modify(rt<<1|1,mid+1,r,ql,qr,d);
	else{
		modify(rt<<1,l,mid,ql,qr,d);
		modify(rt<<1|1,mid+1,r,ql,qr,d);
	}
	pushup(rt);
}
void solve(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(Q--){
		cin>>op;
		if(op==1){
			cin>>l>>r>>d;
			modify(1,1,n,l,r,d);
		}else{
			cin>>l>>r;
			cout<<query(1,1,n,l,r)<<'\n';
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int __=1;//cin>>__;
	while(__--)solve();return 0;
}

线段树打标记2

题意:

 Code:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int mxn=2e5+10;
const int mxe=2e5+10;
const int mod=1e9+7;

struct tag{
	int mul,add;
};

tag operator+(const tag &l,const tag &r){
	return {(l.mul*r.mul)%mod,(l.add*r.mul+r.add)%mod};
}
struct Segtree{
	tag t;
	int val;
	int sz;
}tree[mxe<<2];

int n,Q,x,d,l,r,op;
int a[mxn]; 

void settag(int rt,tag t){
	tree[rt].t=tree[rt].t+t;
	tree[rt].val=(tree[rt].val*t.mul+tree[rt].sz*t.add)%mod;
}
void pushup(int rt){
	tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%mod;
}
void pushdown(int rt){
	if(tree[rt].t.mul!=1||tree[rt].t.add!=0){
		settag(rt<<1,tree[rt].t);
		settag(rt<<1|1,tree[rt].t);
		tree[rt].t={1,0};
	}
}
void build(int rt,int l,int r){
	tree[rt].t={1,0};
	tree[rt].sz=r-l+1;
	if(l==r){
		tree[rt].val=a[l];
		return;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
int query(int rt,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr){
		return tree[rt].val;
	}
	pushdown(rt);
	int mid=l+r>>1;
	if(qr<=mid) return query(rt<<1,l,mid,ql,qr);
	if(ql>mid) return query(rt<<1|1,mid+1,r,ql,qr);
	return (query(rt<<1,l,mid,ql,qr)+query(rt<<1|1,mid+1,r,ql,qr))%mod;
}
void modify(int rt,int l,int r,int ql,int qr,tag t){
	if(ql==l&&r==qr){
		settag(rt,t);
		return;
	}
	pushdown(rt);
	int mid=l+r>>1;
	if(qr<=mid) modify(rt<<1,l,mid,ql,qr,t);
	else if(ql>mid) modify(rt<<1|1,mid+1,r,ql,qr,t);
	else{
		modify(rt<<1,l,mid,ql,mid,t);
		modify(rt<<1|1,mid+1,r,mid+1,qr,t);
	}
	pushup(rt);
}
void solve(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(Q--){
		cin>>op;
		if(op==1){
			cin>>l>>r>>d;
			modify(1,1,n,l,r,(tag){1,d});
		}else if(op==2){
			cin>>l>>r>>d;
			modify(1,1,n,l,r,(tag){d,0});
		}else if(op==3){
			cin>>l>>r>>d;
			modify(1,1,n,l,r,(tag){0,d});
		}else{
			cin>>l>>r;
			cout<<query(1,1,n,l,r)<<'\n';
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int __=1;//cin>>__;
	while(__--)solve();return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值