线段树

线段树+lazy标记

应用:
单点修改(增减)
区间修改(增减)
区间求和(RMQ)
以下代码注意实际问题,把不需要的注释即可。

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x7fffffff;
const int maxn = 1e5 + 10;
struct node{
	int l,r;
	ll sum;
	ll add;
	ll _max,_min;
}tree[maxn * 4];   //一定要开到4倍的空间

ll a[maxn];

void pushup(int p){
	tree[p].sum = tree[p*2].sum + tree[p*2+1].sum;
	tree[p]._max = max(tree[p*2]._max,tree[p*2+1]._max);
	tree[p]._min = min(tree[p*2]._min,tree[p*2+1]._min);
}
void pushdown(int p){
	if(tree[p].add){
		//增减
		tree[p*2].sum += tree[p].add*(tree[p*2].r - tree[p*2].l + 1); 
		tree[p*2+1].sum += tree[p].add*(tree[p*2+1].r - tree[p*2+1].l + 1); 
		tree[p*2]._max += tree[p].add;
		tree[p*2+1]._max += tree[p].add;
		tree[p*2]._min += tree[p]._min;
		tree[p*2+1]._min += tree[p]._min;
		tree[p*2].add += tree[p].add;
		tree[p*2+1].add += tree[p].add;
		tree[p].add = 0;
		//修改,去掉 + 号
		/*tree[p*2].sum = tree[p].add*(tree[p*2].r - tree[p*2].l + 1); 
		tree[p*2+1].sum = tree[p].add*(tree[p*2+1].r - tree[p*2+1].l + 1); 
		tree[p*2]._max = tree[p].add;
		tree[p*2+1]._max = tree[p].add;
		tree[p*2]._min = tree[p]._min;
		tree[p*2+1]._min = tree[p]._min;
		tree[p*2].add = tree[p].add;
		tree[p*2+1].add = tree[p].add;
		tree[p].add = 0;*/
	}
}
void build(int p,int l,int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p].sum = a[l];
		tree[p]._max = a[l];
		tree[p]._min = a[l];
		return ;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid + 1, r);
	pushup(p);
}
void change(int p,int l,int r, int val){  
	if(l <= tree[p].l && tree[p].r <= r){    //区间修改 ,实现单点修改即令 l == r
		//增减
		tree[p].sum += val*(tree[p].r - tree[p].l + 1);
		tree[p].add += val;
		tree[p]._max += val;
		tree[p]._min += val;
		//修改,去掉+号
		/*tree[p].sum = val*(tree[p].r - tree[p].l + 1);
		tree[p].add = val;
		tree[p]._max = val;
		tree[p]._min = val;*/
		return ;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	if(l <= mid) change(p*2, l, r, val);
	if(mid < r) change(p*2+1, l, r, val);
	pushup(p);
}

ll query(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r)
		return tree[p].sum;
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	ll sum = 0;
	ll _max = -inf;
	ll _min = inf;
	if(l <= mid) {
		sum += query(p*2, l, r);
		_max = max(_max,query(p*2,l,r));
		_min = min(_min,query(p*2,l,r));
	}
	if(mid < r) {
		sum += query(p*2+1, l, r);
		_max = max(_max,query(p*2+1,l,r));
		_min = min(_min,query(p*2+1,l,r));
	}
	return sum;
	//return _max;
	//return _min;
}
int main()
{
	int n;
	cin>>n;
	for(int i = 1; i <= n; i++)
		cin>>a[i];
	build(1,1,n);
	return 0;
}

应用一:单点增减区间求和

题目来源hdu1166敌兵布阵

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 50000 + 10;

struct node{
	int l,r;
	int add;
	int sum;
}tree[maxn * 4];

int a[maxn];

void pushup(int p){
	tree[p].sum = tree[p*2].sum + tree[p*2+1].sum;
}
void pushdown(int p){
	if(tree[p].add){
		tree[p*2].sum += tree[p].add*(tree[p*2].r - tree[p*2].l + 1);
		tree[p*2+1].sum += tree[p].add*(tree[p*2+1].r - tree[p*2+1].l + 1);
		tree[p*2].add += tree[p].add;
		tree[p*2+1].add += tree[p].add;
		tree[p].add = 0;
	}
}
void build(int p,int l,int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p].sum = a[l];
		return ;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	pushup(p);
}
void change(int p,int l,int r,int val){
	if(l <= tree[p].l && tree[p].r <= r){
		tree[p].sum += val*(tree[p].r - tree[p].l + 1);
		tree[p].add += val;
		return;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	if(l <= mid) change(p*2,l,r,val);
	if(mid < r) change(p*2+1,l,r,val);
	pushup(p);
}
int query(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r)
		return tree[p].sum;
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	int sum = 0;
	if(l <= mid) sum += query(p*2, l, r);
	if(mid < r) sum += query(p*2+1, l, r);
	return sum; 
}
int main()
{
	int t, cnt = 1;
	cin>>t;
	while(t--){
		int n;
		memset(tree,0, sizeof tree);
		cin>>n;
		for(int i = 1;i<=n;i++)
			scanf("%d",&a[i]);
		build(1,1,n);
		string op;
		int a,b;
		cout<<"Case "<<cnt++<<":"<<endl;
		while(1){
			cin>>op;
			if(op[0] == 'E')
				break;
			cin>>a>>b;
			if(op[0] == 'A')
				change(1,a,a,b);
			else if(op[0] =='S')
				change(1,a,a,-b);
			else if(op[0] == 'Q')
				cout<<query(1,a,b)<<endl;
		}
	}
	return 0;
}

应用二:单点修改区间最值

题目来源hdu1754I Hate It

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 2e5 + 10;
const int inf = 0x7fffffff;

struct node{
	int l,r;
	int add;
	int _max;
}tree[maxn * 4];

int a[maxn];

void pushup(int p){
	tree[p]._max = max(tree[p*2]._max, tree[p*2+1]._max);
}
void pushdown(int p){
	if(tree[p].add){
		tree[p*2]._max = tree[p].add;
		tree[p*2+1]._max = tree[p].add;
		tree[p*2].add = tree[p].add;
		tree[p*2+1].add = tree[p].add;
		tree[p].add = 0; 
	}
}
void build(int p,int l,int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p]._max = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	pushup(p);
}
void change(int p,int l,int r,int val){
	if(l <= tree[p].l && tree[p].r <= r){
		tree[p]._max = val;
		tree[p].add = val;
		return;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	if(l <= mid) change(p*2,l,r,val);
	if(mid < r) change(p*2+1,l,r,val);
	pushup(p);
}
int query(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r){
		return tree[p]._max;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	int _max = -inf;
	if(l <= mid) _max = max(_max,query(p*2,l,r));
	if(mid < r) _max = max(_max,query(p*2+1,l,r));
	return _max;
}
int main()
{
	int n,m;
	while(cin>>n>>m){
		for(int i = 1;i<=n;i++)
			scanf("%d",&a[i]);
		build(1,1,n);
		string op;
		int a,b;
		while(m--){
			//getchar();
			cin>>op>>a>>b;
			if(op[0] == 'Q'){
				cout<<query(1,a,b)<<endl;
			}else if(op[0] == 'U'){	
				change(1,a,a,b);
			}

		}

	}

	return 0;
}

应用三:区间加减区间求和

题目来源poj3468A Simple Problem with Integers

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
struct node{
	int l,r;
	ll sum;
	ll add;
}tree[maxn * 4];

ll a[maxn];

void pushup(int p){
	tree[p].sum = tree[p*2].sum + tree[p*2+1].sum;
}
void pushdown(int p){
	if(tree[p].add){
		tree[p*2].sum += tree[p].add*(tree[p*2].r - tree[p*2].l + 1); 
		tree[p*2+1].sum += tree[p].add*(tree[p*2+1].r - tree[p*2+1].l + 1); 
		tree[p*2].add += tree[p].add;
		tree[p*2+1].add += tree[p].add;
		tree[p].add = 0;
	}
}
void build(int p,int l,int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p].sum = a[l];
		return ;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid + 1, r);
	pushup(p);
}
void change(int p,int l,int r, int val){
	if(l <= tree[p].l && tree[p].r <= r){
		tree[p].sum += val*(tree[p].r - tree[p].l + 1);
		tree[p].add += val;
		return ;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	if(l <= mid) change(p*2, l, r, val);
	if(mid < r) change(p*2+1, l, r, val);
	pushup(p);
}
ll querysum(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r)
		return tree[p].sum;
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	ll ans = 0;
	if(l <= mid) ans += querysum(p*2, l, r);
	if(mid < r) ans += querysum(p*2+1, l, r);
	return ans;
}
int main()
{
	int n,q;
	cin>>n>>q;
	for(int i = 1;i <= n; i++)
		scanf("%lld", &a[i]);
	build(1, 1, n);
	char op;
	while(q--){
		//cin>>op;
		getchar();
		scanf("%c",&op);
		if(op == 'Q'){
			int l,r;
			scanf("%d%d",&l,&r);
			cout<<querysum(1,l,r)<<endl;
		}
		else if(op == 'C'){
			int l ,r ,val;
			scanf("%d%d%d",&l,&r,&val);
			change(1,l,r,val);
		}
	}
	return 0;
}

应用四:区间修改区间求和

题目来源hihoCoder1078线段树的区间修改

#include <iostream>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
struct node{
	int l ,r;
	int add;
	ll sum;
}tree[maxn * 4];

int a[maxn];

void pushup(int p){
	tree[p].sum = tree[p*2].sum + tree[p*2+1].sum;
}
void pushdown(int p){
	if(tree[p].add){
		tree[p*2].sum = tree[p].add*(tree[p*2].r - tree[p*2].l + 1);
		tree[p*2+1].sum = tree[p].add*(tree[p*2+1].r - tree[p*2+1].l + 1);
		tree[p*2].add = tree[p].add;
		tree[p*2+1].add = tree[p].add;
		tree[p].add = 0;
	}
}
void build(int p, int l,int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p].sum = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid + 1, r);
	pushup(p);
}
void change(int p,int l,int r,int val){
	if(l <= tree[p].l && tree[p].r <= r){
		tree[p].sum = val*(tree[p].r - tree[p].l + 1);
		tree[p].add = val;
		return;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	if(l <= mid) change(p*2, l, r, val);
	if(mid < r) change(p*2+1, l, r, val);
	pushup(p);
}
ll query(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r){
		return tree[p].sum;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) / 2;
	ll sum = 0;
	if(l <= mid) sum += query(p*2,l,r);
	if(mid < r) sum += query(p*2+1,l,r);
	return sum;
}
int main()
{
	int n,q,op,b,c,d;
	cin>>n;
	for(int i = 1;i <= n;i++)
		cin>>a[i];
	build(1,1,n);
	cin>>q;
	while(q--){
		cin>>op;
		if(op == 1){
			cin>>b>>c>>d;
			change(1,b,c,d);
		}
		else if(op == 0){
			cin>>b>>c;
			cout<<query(1,b,c)<<endl;
		}
	}
	return 0;
}

应用五:查询最大连续子段和

题目来源CH4301 Can you answer on these queries III
查询函数里面的判断条件一直搞错了,弄了好几个小时

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 10;

struct node{
	int l, r;
	int sum;
	int lmax,rmax,smax;
}tree[maxn * 4];

int a[maxn];

void pushup(int p){
	tree[p].sum = tree[p*2].sum + tree[p*2+1].sum;
	tree[p].lmax = max(tree[p*2].lmax, tree[p*2].sum + tree[p*2+1].lmax);
	tree[p].rmax = max(tree[p*2+1].rmax, tree[p*2+1].sum + tree[p*2].rmax);
	tree[p].smax = max(max(tree[p*2].smax,tree[p*2+1].smax), tree[p*2].rmax + tree[p*2+1].lmax);
}
void build(int p, int l, int r){
	tree[p].l = l; tree[p].r = r;
	if(l == r){
		tree[p].sum = a[l];
		tree[p].lmax = a[l];
		tree[p].rmax = a[l];
		tree[p].smax = a[l];
		return ;
	}
	int mid = (l + r) / 2;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	pushup(p);
} 
void change(int p,int pos,int val){
	if(tree[p].l == tree[p].r){
		tree[p].sum = val;
		tree[p].lmax = val;
		tree[p].rmax = val;
		tree[p].smax = val;
		return ;
	}
	int mid = (tree[p].l + tree[p].r) / 2;
	if(pos <= mid) change(p*2, pos, val);
	else  change(p*2+1, pos, val);
	pushup(p);
}
node query(int p,int l,int r){
	if(l <= tree[p].l && tree[p].r <= r)
		return tree[p];
	int mid = (tree[p].l + tree[p].r) / 2;
	if(r <= mid) return query(p*2, l ,r);    //注意判断条件,原来一直错在这里
	if(mid < l) return query(p*2+1, l, r);
	node ans, lson = query(p*2, l, r), rson = query(p*2+1, l, r);
	ans.sum = lson.sum + rson.sum;
	ans.lmax = max(lson.lmax, lson.sum + rson.lmax);
	ans.rmax = max(rson.rmax, rson.sum + lson.rmax);
	ans.smax = max(max(lson.smax,rson.smax), lson.rmax + rson.lmax);
	return ans; 
}
int main()
{
	int n, m;
	cin>>n>>m;
	for (int i = 1; i <= n; ++i){
		cin>>a[i];
	}
	build(1,1,n);
	int op,x,y;
	while(m--){
		cin>>op>>x>>y;
		if(op == 1){
			if(x>y) swap(x,y);
			cout<<query(1,x,y).smax<<endl;
		}
		else if(op == 2){
			change(1,x,y);	
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值