维护一个矩阵,实现以下几个需求:
①
:
①:
①:单点修改,区间查最值
②
:
②:
②:区间加,区间查和
③
:
③:
③:区间修改(递增),区间查最值
二维线段树本质上是树套树
因此无法实现
p
u
s
h
d
o
w
n
pushdown
pushdown,用标记永久化替代
暂时无法满足任意模式的区间修改,也可能是我太菜了
注意修改后的
m
e
r
g
e
merge
merge,只针对所修改区间进行
m
e
r
g
e
merge
merge 即可
参考:线段树套线段树
建树复杂度:
O
(
n
2
)
O(n^2)
O(n2)
单次修改查询复杂度:
O
(
l
o
g
2
n
)
O(log^2n)
O(log2n)
例题一:Census UVA - 11297
建树后,单点修改,区间查最大最小值
// https://vjudge.net/problem/UVA-11297
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 5e2 + 5;
int n, q;
ll a[maxn][maxn];
struct seg{
ll t1[maxn<<2], t2[maxn<<2], lz[maxn<<2];
void build(int L, int l, int r, int rt){
if(l == r) {
t1[rt] = t2[rt] = a[L][r];
return;
}
int m = l + r >> 1;
build(L, l, m, rt<<1);
build(L, m+1, r, rt<<1|1);
t1[rt] = max(t1[rt<<1], t1[rt<<1|1]);
t2[rt] = min(t2[rt<<1], t2[rt<<1|1]);
}
void update(int L, int R, ll x, int l, int r, int rt){
t1[rt] = t2[rt] = x;
if(l==L && r==R){
lz[rt] = x;
return;
}
int m = l + r >> 1;
if(m >= R) update(L, R, x, l, m, rt<<1);
else if(L > m) update(L, R, x, m+1, r, rt<<1|1);
else update(L, m, x, l, m, rt<<1), \
update(m+1, R, x, m+1, r, rt<<1|1);
t1[rt] = max(t1[rt<<1], t1[rt<<1|1]);
t2[rt] = min(t2[rt<<1], t2[rt<<1|1]);
}
ll query1(int L, int R, int l, int r, int rt, ll sum){
if(l==L && r==R) return t1[rt];
// sum += lz[rt];
int m = l + r >> 1;
if(m >= R) return query1(L, R, l, m, rt<<1, sum);
else if(L > m) return query1(L, R, m+1, r, rt<<1|1, sum);
else return max( query1(L, m, l, m, rt<<1, sum), \
query1(m+1, R, m+1, r, rt<<1|1, sum) );
}
ll query2(int L, int R, int l, int r, int rt, ll sum){
if(l==L && r==R) return t2[rt];
// sum += lz[rt];
int m = l + r >> 1;
if(m >= R) return query2(L, R, l, m, rt<<1, sum);
else if(L > m) return query2(L, R, m+1, r, rt<<1|1, sum);
else return min( query2(L, m, l, m, rt<<1, sum), \
query2(m+1, R, m+1, r, rt<<1|1, sum) );
}
} t[maxn<<2], lz[maxn<<2];
void merge(seg &p, seg &p1, seg &p2, int L, int R, int l, int r, int rt){
if(l>R || r<L) return;
p.t1[rt] = max(p1.t1[rt], p2.t1[rt]);
p.t2[rt] = min(p1.t2[rt], p2.t2[rt]);
if(l == r) return;
int m = l + r >> 1;
merge(p, p1, p2, L, R, l, m, rt<<1);
merge(p, p1, p2, L, R, m+1, r, rt<<1|1);
}
void build(int l, int r, int rt){
if(l == r){
t[rt].build(l, 1, n, 1);
return;
}
int m = l + r >> 1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], 1, n, 1, n, 1);
}
void update(int x, int y, int xx, int yy, ll v, int l, int r, int rt){
t[rt].update(y, yy, v, 1, n, 1);
if(l==x && r==xx){
lz[rt].update(y, yy, v, 1, n, 1);
return;
}
int m = l + r >> 1;
if(m >= xx) update(x, y, xx, yy, v, l, m, rt<<1);
else if(x > m) update(x, y, xx, yy, v, m+1, r, rt<<1|1);
else update(x, y, m, yy, v, l, m, rt<<1), \
update(m+1, y, xx, yy, v, m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], y, yy, 1, n, 1);
}
ll query1(int x, int y, int xx, int yy, int l, int r, int rt, ll sum){
if(l==x && r==xx) return t[rt].query1(y, yy, 1, n, 1, 0);
// sum += lz[rt].query(y, yy, 1, n, 1, 0);
int m = l + r >> 1;
if(m >= xx) return query1(x, y, xx, yy, l, m, rt<<1, sum);
else if(x > m) return query1(x, y, xx, yy, m+1, r, rt<<1|1, sum);
else return max( query1(x, y, m, yy, l, m, rt<<1, sum), \
query1(m+1, y, xx, yy, m+1, r, rt<<1|1, sum) );
}
ll query2(int x, int y, int xx, int yy, int l, int r, int rt, ll sum){
if(l==x && r==xx) return t[rt].query2(y, yy, 1, n, 1, 0);
// sum += lz[rt].query(y, yy, 1, n, 1, 0);
int m = l + r >> 1;
if(m >= xx) return query2(x, y, xx, yy, l, m, rt<<1, sum);
else if(x > m) return query2(x, y, xx, yy, m+1, r, rt<<1|1, sum);
else return min( query2(x, y, m, yy, l, m, rt<<1, sum), \
query2(m+1, y, xx, yy, m+1, r, rt<<1|1, sum) );
}
int main() {
scanf("%d", &n);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%lld", &a[i][j]);
build(1, n, 1);
scanf("%d", &q);
while(q--){
char op; int x, y, xx, yy, w;
scanf(" %c", &op);
if(op == 'c') {
scanf("%d %d %d", &x, &y, &w);
update(x, y, x, y, w, 1, n, 1);
} else {
scanf("%d %d %d %d", &x, &y, &xx, &yy);
printf("%lld ", query1(x, y, xx, yy, 1, n, 1, 0));
printf("%lld\n", query2(x, y, xx, yy, 1, n, 1, 0));
}
}
}
例题二:Census UVA - 11297
查询区间最大值,用最大值
+
+
+
w
w
w 更新区间
注意这里因为标记可以不断取
m
a
x
max
max,才可以实现区间更新
// https://www.luogu.com.cn/problem/P3437
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 2;
int d, s, q;
struct seg{
int t[maxn<<2], lz[maxn<<2];
void build(int L, int l, int r, int rt){
if(l == r) {
// t[rt] = a[L][r];
return;
}
int m = l + r >> 1;
build(L, l, m, rt<<1);
build(L, m+1, r, rt<<1|1);
t[rt] = max(t[rt<<1], t[rt<<1|1]);
}
void update(int L, int R, int x, int l, int r, int rt){
t[rt] = max(t[rt], x);
if(l==L && r==R){
lz[rt] = max(lz[rt], x);
return;
}
int m = l + r >> 1;
if(m >= R) update(L, R, x, l, m, rt<<1);
else if(L > m) update(L, R, x, m+1, r, rt<<1|1);
else update(L, m, x, l, m, rt<<1), \
update(m+1, R, x, m+1, r, rt<<1|1);
// t[rt] = max(t[rt<<1], t[rt<<1|1]);
}
int query(int L, int R, int l, int r, int rt){
if(l==L && r==R) return t[rt];
int m = l + r >> 1, ret = lz[rt];
if(m >= R) ret = max(ret, query(L, R, l, m, rt<<1));
else if(L > m) ret = max(ret, query(L, R, m+1, r, rt<<1|1));
else ret = max(ret, max( query(L, m, l, m, rt<<1), \
query(m+1, R, m+1, r, rt<<1|1) ) );
return ret;
}
} t[maxn<<2], lz[maxn<<2];
void merge(seg &p, seg &p1, seg &p2, int l, int r, int rt){
p.t[rt] = max(p1.t[rt], p2.t[rt]);
if(l == r) return;
int m = l + r >> 1;
merge(p, p1, p2, l, m, rt<<1);
merge(p, p1, p2, m+1, r, rt<<1|1);
}
void build(int l, int r, int rt){
if(l == r){
t[rt].build(l, 1, s, 1);
return;
}
int m = l + r >> 1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], 1, s, 1);
}
void update(int x, int y, int xx, int yy, int v, int l, int r, int rt){
t[rt].update(y, yy, v, 1, s, 1);
if(l==x && r==xx){
lz[rt].update(y, yy, v, 1, s, 1);
return;
}
int m = l + r >> 1;
if(m >= xx) update(x, y, xx, yy, v, l, m, rt<<1);
else if(x > m) update(x, y, xx, yy, v, m+1, r, rt<<1|1);
else update(x, y, m, yy, v, l, m, rt<<1), \
update(m+1, y, xx, yy, v, m+1, r, rt<<1|1);
// merge(t[rt], t[rt<<1], t[rt<<1|1], 1, s, 1);
}
int query(int x, int y, int xx, int yy, int l, int r, int rt){
if(l==x && r==xx) return t[rt].query(y, yy, 1, s, 1);
int m = l + r >> 1, ret = lz[rt].query(y, yy, 1, s, 1);
if(m >= xx) ret = max(ret, query(x, y, xx, yy, l, m, rt<<1));
else if(x > m) ret = max(ret, query(x, y, xx, yy, m+1, r, rt<<1|1));
else ret = max(ret, max( query(x, y, m, yy, l, m, rt<<1), \
query(m+1, y, xx, yy, m+1, r, rt<<1|1) ) );
return ret;
}
int main() {
scanf("%d%d%d", &d, &s, &q);
while(q--){
int di, si, w, x, y;
scanf("%d %d %d %d %d", &di, &si, &w, &x, &y);
x++, y++;
w += query(x, y, x+di-1, y+si-1, 1, d, 1);
update(x, y, x+di-1, y+si-1, w, 1, d, 1);
}
printf("%d\n", query(1, 1, d, s, 1, d, 1));
}
例题三:Mosaic - HDU 4819
建树后,查询区间最大最小值,单点更新
// https://vjudge.net/problem/HDU-4819
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 8e2 + 5;
int T, n, q;
int a[maxn][maxn];
struct seg{
int t1[maxn<<2], t2[maxn<<2], lz[maxn<<2];
void build(int L, int l, int r, int rt){
if(l == r) {
t1[rt] = t2[rt] = a[L][r];
return;
}
int m = l + r >> 1;
build(L, l, m, rt<<1);
build(L, m+1, r, rt<<1|1);
t1[rt] = max(t1[rt<<1], t1[rt<<1|1]);
t2[rt] = min(t2[rt<<1], t2[rt<<1|1]);
}
void update(int L, int R, ll x, int l, int r, int rt){
t1[rt] = t2[rt] = x;
if(l==L && r==R){
lz[rt] = x;
return;
}
int m = l + r >> 1;
if(m >= R) update(L, R, x, l, m, rt<<1);
else if(L > m) update(L, R, x, m+1, r, rt<<1|1);
else update(L, m, x, l, m, rt<<1), \
update(m+1, R, x, m+1, r, rt<<1|1);
t1[rt] = max(t1[rt<<1], t1[rt<<1|1]);
t2[rt] = min(t2[rt<<1], t2[rt<<1|1]);
}
ll query1(int L, int R, int l, int r, int rt, ll sum){
if(l==L && r==R) return t1[rt];
// sum += lz[rt];
int m = l + r >> 1;
if(m >= R) return query1(L, R, l, m, rt<<1, sum);
else if(L > m) return query1(L, R, m+1, r, rt<<1|1, sum);
else return max( query1(L, m, l, m, rt<<1, sum), \
query1(m+1, R, m+1, r, rt<<1|1, sum) );
}
ll query2(int L, int R, int l, int r, int rt, ll sum){
if(l==L && r==R) return t2[rt];
// sum += lz[rt];
int m = l + r >> 1;
if(m >= R) return query2(L, R, l, m, rt<<1, sum);
else if(L > m) return query2(L, R, m+1, r, rt<<1|1, sum);
else return min( query2(L, m, l, m, rt<<1, sum), \
query2(m+1, R, m+1, r, rt<<1|1, sum) );
}
} t[maxn<<2], lz[maxn<<2];
void merge(seg &p, seg &p1, seg &p2, int L, int R, int l, int r, int rt){
if(l>R || r<L) return;
p.t1[rt] = max(p1.t1[rt], p2.t1[rt]);
p.t2[rt] = min(p1.t2[rt], p2.t2[rt]);
if(l == r) return;
int m = l + r >> 1;
merge(p, p1, p2, L, R, l, m, rt<<1);
merge(p, p1, p2, L, R, m+1, r, rt<<1|1);
}
void build(int l, int r, int rt){
if(l == r){
t[rt].build(l, 1, n, 1);
return;
}
int m = l + r >> 1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], 1, n, 1, n, 1);
}
void update(int x, int y, int xx, int yy, ll v, int l, int r, int rt){
t[rt].update(y, yy, v, 1, n, 1);
if(l==x && r==xx){
lz[rt].update(y, yy, v, 1, n, 1);
return;
}
int m = l + r >> 1;
if(m >= xx) update(x, y, xx, yy, v, l, m, rt<<1);
else if(x > m) update(x, y, xx, yy, v, m+1, r, rt<<1|1);
else update(x, y, m, yy, v, l, m, rt<<1), \
update(m+1, y, xx, yy, v, m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], y, yy, 1, n, 1);
}
ll query1(int x, int y, int xx, int yy, int l, int r, int rt, ll sum){
if(l==x && r==xx) return t[rt].query1(y, yy, 1, n, 1, 0);
// sum += lz[rt].query(y, yy, 1, n, 1, 0);
int m = l + r >> 1;
if(m >= xx) return query1(x, y, xx, yy, l, m, rt<<1, sum);
else if(x > m) return query1(x, y, xx, yy, m+1, r, rt<<1|1, sum);
else return max( query1(x, y, m, yy, l, m, rt<<1, sum), \
query1(m+1, y, xx, yy, m+1, r, rt<<1|1, sum) );
}
ll query2(int x, int y, int xx, int yy, int l, int r, int rt, ll sum){
if(l==x && r==xx) return t[rt].query2(y, yy, 1, n, 1, 0);
// sum += lz[rt].query(y, yy, 1, n, 1, 0);
int m = l + r >> 1;
if(m >= xx) return query2(x, y, xx, yy, l, m, rt<<1, sum);
else if(x > m) return query2(x, y, xx, yy, m+1, r, rt<<1|1, sum);
else return min( query2(x, y, m, yy, l, m, rt<<1, sum), \
query2(m+1, y, xx, yy, m+1, r, rt<<1|1, sum) );
}
int main() {
scanf("%d", &T);
for(int cas=1; cas<=T; cas++){
scanf("%d", &n);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%lld", &a[i][j]);
build(1, n, 1);
scanf("%d", &q);
printf("Case #%d:\n", cas);
while(q--){
int x, y, L;
scanf("%d %d %d", &x, &y, &L);
int x1 = max(x - L / 2, 1);
int x2 = min(x + L / 2, n);
int y1 = max(y - L / 2, 1);
int y2 = min(y + L / 2, n);
int mx = query1(x1, y1, x2, y2, 1, n, 1, 0);
int mi = query2(x1, y1, x2, y2, 1, n, 1, 0);
int w = (mx + mi) / 2;
printf("%d\n", w);
update(x, y, x, y, w, 1, n, 1);
}
}
}
例题四:SuperBrother打鼹鼠
单点加,查询区间和
注意这份代码也可以满足区间加,查询区间和
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 1024 + 5;
int n;
ll a[maxn][maxn];
struct seg{
ll t[maxn<<2], lz[maxn<<2];
void build(int L, int l, int r, int rt){
if(l == r) {
t[rt] = a[L][r];
return;
}
int m = l + r >> 1;
build(L, l, m, rt<<1);
build(L, m+1, r, rt<<1|1);
t[rt] = t[rt<<1] + t[rt<<1|1];
}
void update(int L, int R, ll x, int l, int r, int rt){
if(l>R || r<L) return;
t[rt] += 1ll * x * (R - L + 1);
if(l==L && r==R){
lz[rt] += x;
return;
}
int m = l + r >> 1;
if(m >= R) update(L, R, x, l, m, rt<<1);
else if(L > m) update(L, R, x, m+1, r, rt<<1|1);
else update(L, m, x, l, m, rt<<1), \
update(m+1, R, x, m+1, r, rt<<1|1);
}
ll query(int L, int R, int l, int r, int rt, ll sum){
if(l>R || r<L) return 0;
if(l==L && r==R) return t[rt] + sum * (r - l + 1);
sum += lz[rt];
int m = l + r >> 1;
if(m >= R) return query(L, R, l, m, rt<<1, sum);
else if(L > m) return query(L, R, m+1, r, rt<<1|1, sum);
else return query(L, m, l, m, rt<<1, sum) +
query(m+1, R, m+1, r, rt<<1|1, sum);
}
} t[maxn<<2], lz[maxn<<2];
void merge(seg p, seg p1, seg p2, int l, int r, int rt){
p.t[rt] = p1.t[rt] + p2.t[rt];
if(l == r) return;
int m = l + r >> 1;
merge(p, p1, p2, l, m, rt<<1);
merge(p, p1, p2, m+1, r, rt<<1|1);
}
void build(int l, int r, int rt){
if(l == r){
t[rt].build(l, 1, n, 1);
return;
}
int m = l + r >> 1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
merge(t[rt], t[rt<<1], t[rt<<1|1], 1, n, 1);
}
void update(int x, int y, int xx, int yy, ll v, int l, int r, int rt){
if(l>xx || r<x) return;
t[rt].update(y, yy, 1ll * v * (xx - x + 1), 1, n, 1);
if(l==x && r==xx){
lz[rt].update(y, yy, v, 1, n, 1);
return;
}
int m = l + r >> 1;
if(m >= xx) update(x, y, xx, yy, v, l, m, rt<<1);
else if(x > m) update(x, y, xx, yy, v, m+1, r, rt<<1|1);
else update(x, y, m, yy, v, l, m, rt<<1), \
update(m+1, y, xx, yy, v, m+1, r, rt<<1|1);
}
ll query(int x, int y, int xx, int yy, int l, int r, int rt, ll sum){
if(l>xx || r<x) return 0;
if(l==x && r==xx) return t[rt].query(y, yy, 1, n, 1, 0) + sum * (r - l + 1);
sum += lz[rt].query(y, yy, 1, n, 1, 0);
int m = l + r >> 1; ll ret = 0;
if(m >= xx) return query(x, y, xx, yy, l, m, rt<<1, sum);
else if(x > m) return query(x, y, xx, yy, m+1, r, rt<<1|1, sum);
else return query(x, y, m, yy, l, m, rt<<1, sum) +
query(m+1, y, xx, yy, m+1, r, rt<<1|1, sum) ;
}
int main() {
scanf("%d", &n);
while(1){
int m, x1, y1, x2, y2, w;
scanf("%d", &m);
if(m == 3) break;
if(m == 1){
scanf("%d%d%d", &x1, &y1, &w);
x1++, y1++, x2++, y2++;
update(x1, y1, x1, y1, w, 1, n, 1);
} else {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
x1++, y1++, x2++, y2++;
printf("%lld\n", query(x1, y1, x2, y2, 1, n, 1, 0));
}
}
}