|算法讨论|线段树1(大白书版本) 学习笔记

常用方法:

1、点修改,区间查询

2、区间增加,区间查询

3、区间修改,区间查询

4、混合多种修改,区间查询

5、离散化操作

6、二维线段树


1、点修改,区间查询

input:
10 6
5 4 8 9 7 2 4 1 5 7
1 1 10
0 8 6
1 1 10
1 2 5
0 4 -8
1 1 5
//n m
//n个数,表示线段树节点的初始值
//m行,每行一个指令
//0 p v,修改p节点为v
//1 x y,求x~y区间最小值

output:
1
2
4
-8
#include
#include
#include
#include
#include
#define ms(i,j) memset(i,j,sizeof i);
using namespace std;
const int MAXN = 1000 + 5;
int n,m;
int mino[MAXN];//最小值 
int p,v; 
int update(int o, int l, int r)//更新a[p] = v; 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (l==r) mino[o] = v;
	else
	{
		if (p<=m) update(lc, l, m); else update(rc, m+1, r);
		mino[o] = min(mino[lc], mino[rc]);
	}
}
int x,y;
int query(int o, int l ,int r)//查询x,y区间最小值 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	int ans = 100000000;
	if (x<=l&&r<=y) return mino[o];
	if (x<=m) ans = min(ans, query(lc, l, m));
	if (m


2、区间增加,区间查询

input:
10 10
5 4 8 9 7 2 4 1 5 7
1 1 10
2 1 10
3 1 10
0 6 7 10
2 2 8
3 2 5
0 4 6 -7
3 4 8
0 10 10 -17
2 7 10
//n m
//n个数,表示线段树节点的初始值
//m行,每行一个指令
//0 x y v,把x~y增加v
//1 x y,求x~y区间和
//2 x y,求x~y区间最小值
//3 x y,求x~y区间最大值
output:
52
1
9
1
9
14
-10
#include
#include
#include
#define ms(i,j) memset(i,j,sizeof i);
using namespace std;
const int MAXN = 1000 + 5;
int n,m;
int _max, _min, _sum;
int maxv[MAXN], minv[MAXN], addv[MAXN], sumv[MAXN]; 
int mt(int o, int l, int r)//更新结点信息 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (r>l)
	{
		sumv[o] = sumv[lc]+sumv[rc];
		minv[o] = min(minv[lc], minv[rc]);
		maxv[o] = max(maxv[lc], maxv[rc]);
	} 
	minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += (r-l+1)*addv[o];
}
int x,y,v;
int update(int o, int l, int r)//使x,y区间都加上v 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (x<=l&&r<=y)
	{
		addv[o] = v;
	} else
	{
		if (x<=m) update(lc, l, m);
		if (m


3、区间修改,区间查询

input:
10 10
5 4 8 9 7 2 4 1 5 7
1 1 10
2 1 10
3 1 10
0 6 7 10
2 2 8
3 2 5
0 4 6 2
3 4 8
0 10 10 17
2 7 10
//n m
//n个数,表示线段树节点的初始值
//m行,每行一个指令
//0 x y v,把x~y修改为v(v>=0)
//1 x y,求x~y区间和
//2 x y,求x~y区间最小值
//3 x y,求x~y区间最大值
output:
52
1
9
1
9
10
1
#include
#include
#include
#define ms(i,j) memset(i,j,sizeof i);
using namespace std;
const int MAXN = 1000 + 5;
int _max, _min, _sum;
int setv[MAXN], minv[MAXN], maxv[MAXN], sumv[MAXN];
int n,m;
int pushdown(int o)//标记下传 
{	
	int lc = o*2, rc = o*2+1;
	if (setv[o]>=0)
	{
		setv[lc] = setv[rc] = setv[o];
		setv[o] = -1;
	}
}
int mt(int o, int l, int r)//更新结点信息 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (r>l)
	{
		sumv[o] = sumv[lc] + sumv[rc];
		minv[o] = min(minv[lc], minv[rc]);
		maxv[o] = max(maxv[lc], maxv[rc]);
	}
	if (setv[o]>=0) {minv[o]=maxv[o]=setv[o]; sumv[o] = setv[o]*(r-l+1);}
}
int x,y,v; 
int update(int o, int l, int r)//修改x,y区间值为v 
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (x<=l&&r<=y) 
	{
	    setv[o] = v;
	} else
	{
		pushdown(o);
		if (x<=m) update(lc, l, m); else mt(lc, l, m);
		if (m=0)
	{
		_sum += setv[o] * (min(r,y)-max(l,x)+1);
		_min = min(_min, setv[o]);
		_max = max(_max, setv[o]);
	} else if (x<=l&&r<=y)
	{
		_sum += sumv[o];
		_min = min(_min, minv[o]);
		_max = max(_max, maxv[o]);
	} else
	{
		if (x<=m) query(lc, l, m);
		if (m

4、混合多种修改,区间查询

(1) 修改+增加

input:
10 10
1 2 3 4 5 6 7 8 9 10
2 1 10
0 2 4 5
2 1 6
1 2 7 2
2 3 9
1 1 10 3
2 8 9
0 2 6 2
2 3 7
2 10 10
//n,m
//n个数,表示线段树初值
//m行,每行一个指令
//0 x y v          x,y区间值全部修改为v(v>=0)
//1 x y v          x,y区间值全部增加v
//2 x y            输出x,y区间最小值、最大值、区间和
output:
min:1 max:10 sum:55
min:1 max:6 sum:27
min:7 max:9 sum:55
min:11 max:12 sum:23
min:2 max:12 sum:20
min:13 max:13 sum:13
#include
#include
#include
#define ms(i,j) memset(i,j,sizeof i);
using namespace std;
const int MAXN = 1000 + 5;
int n,m; 
int _max, _min, _sum;
int maxv[MAXN], minv[MAXN], sumv[MAXN], addv[MAXN], setv[MAXN];
int mt(int o, int l, int r)
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	sumv[o] = minv[o] = maxv[o] = 0;
	if (setv[o]>=0)
	{
		sumv[o] = setv[o]*(r-l+1); 
		minv[o] = maxv[o] = setv[o];
	}  else if (r>l)
	{
		sumv[o] = sumv[lc]+sumv[rc];
		minv[o] = min(minv[lc], minv[rc]);
		maxv[o] = max(maxv[lc], maxv[rc]);
	}
	if (addv[o]!=0) {sumv[o] += addv[o] * (r-l+1); minv[o] += addv[o]; maxv[o] += addv[o];}
}
int pushdown(int o)
{
	int lc = o*2, rc = o*2+1;
	if (setv[o]>=0)
	{
		setv[lc] = setv[rc] = setv[o];
		addv[lc] = addv[rc] = 0;//传下去一定要删除add标记 
		setv[o] = -1;
	}
	if (addv[o]!=0)
	{
		addv[lc] += addv[o]; 
		addv[rc] += addv[o]; 
		addv[o] = 0;
	}
}
int x,y,v;
int update_add(int o, int l, int r)
{
	int m = (l+r)/2;
	int lc = o*2, rc = o*2+1;
	if (x<=l&&r<=y) addv[o] += v;
	else
	{
		if (x<=m) update_add(lc, l, m); 
		if (m=0)
	{
		_sum += (setv[o]+add+addv[o])*(min(y,r)-max(x,l)+1);
		_min = min(_min, setv[o]+add+addv[o]);
		_max = max(_max, setv[o]+add+addv[o]);
	} else if (x<=l&&r<=y) 
	{
		_sum += sumv[o]+add*(r-l+1);
		_min = min(_min, minv[o]+add);
		_max = max(_max, maxv[o]+add);
	} else
	{
		if (x<=m) query(lc, l, m,add+addv[o]);
		if (m
(2)增加+乘法

https://www.luogu.org/problem/show?pid=3373









你可能感兴趣的:(算法讨论,树,-,线段树)