常用方法:
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
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
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
(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