此题也是无数WA。
其中的各种细节处理,对理解线段树有很大的帮助。
给出一个数据的示例
input:
1 4 13
2 1 1 1 4 5
2 1 2 1 3 4
1 1 1 1 4 1
3 1 1 1 4
3 1 2 1 3
1 1 4 1 4 100
3 1 3 1 4
2 1 2 1 3 0
2 1 1 1 2 1
3 1 1 1 4
1 1 2 1 4 2
3 1 1 1 4
3 1 1 1 2
初始状态,各节点的minv,maxv,sumv为0,setv=-1

第一步操作

第二、三步操作后

第六步操作后

第八步操作后

第九步操作后

第十一步操作后

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <time.h>
#include <errno.h>
using namespace std;
#define MIN(a, b) a < b ? a : b
#define MAX(a, b) a > b ? a : b
#define F(i, n) for (int i=0;i<(n);++i)
#define REP(i, s, t) for(int i=s;i<=t;++i)
#define UREP(i, s, t) for(int i=s;i>=t;--i)
#define REPOK(i, s, t, o) for(int i=s;i<=t && o;++i)
#define MEM0(addr, size) memset(addr, 0, size)
#define LBIT(x) x&-x
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define eps 1e-15
#define MAXN 1000000
#define MAXM 20
#define MOD 20071027
typedef long long LL;
const double maxdouble = numeric_limits<double>::max();
const int INF = 0x7FFFFFFF;
const int maxnode = 1 << 21; // 修改以确保足够大
struct IntervalTree {
int minv[maxnode + 1];
int maxv[maxnode + 1];
int sumv[maxnode + 1];
int addv[maxnode + 1];
int setv[maxnode + 1];
int length;
int p, v;
int qL, qR;
int _min, _max, _sum;
void init(int n) {
length = n;
}
//_query的封装
void query(int L, int R) {
qL = L;
qR = R;
_min = INF;
_max = -INF;
_sum = 0;
_query(1, 1, length, 0);
}
void _query(int o, int L, int R, int add) {
if (setv[o] >= 0) {
_min = min(_min, minv[o]+add);
_max = max(_max, maxv[o]+add);
_sum += (min(R, qR) - max(L, qL) + 1)*(setv[o]+add+addv[o]);
return;
}
if (qL <= L && qR >= R) {
_min = min(_min, minv[o]+add);
_max = max(_max, maxv[o]+add);
_sum += sumv[o] + (R-L+1)*add;
} else {
int M = L + (R-L)/2;
int lc = 2*o, rc = 2*o+1;
if (qL <= M)
_query(lc, L, M, add+addv[o]);
if (qR > M)
_query(rc, M+1, R, add+addv[o]);
}
}
void add(int L, int R, int v) {
this->v = v;
qL = L;
qR = R;
_add(1, 1, length);
}
void _add(int o, int L, int R) {
if (qL <= L && qR >= R) {
addv[o] += v;
} else {
pushdown(o);
int M = L + (R-L)/2;
int lc = 2*o, rc = 2*o+1;
if (qL <= M)
_add(lc, L, M);
else
maintain(lc, L, M);
if (qR > M)
_add(rc, M+1, R);
else
maintain(rc, M+1, R);
}
maintain(o, L, R);
}
void setto(int L, int R, int v) {
qL = L;
qR = R;
this->v = v;
_set(1, 1, length);
}
void _set(int o, int L, int R) {
if (qL <= L && qR >= R) {
setv[o] = v;
addv[o] = 0; // set操作清除add
} else {
pushdown(o);
int M = L + (R-L)/2;
int lc = 2*o, rc = 2*o+1;
if (qL <= M)
_set(lc, L, M);
else
maintain(lc, L, M); // 要维护不递归的子树
if (qR > M)
_set(rc, M+1, R);
else
maintain(rc, M+1, R);
}
maintain(o, L, R);
}
void pushdown(int o) {
int lc = o*2, rc = o*2+1;
if (setv[o] >= 0) { // setv = -1 表示没有set
setv[lc] = setv[rc] = setv[o];
addv[lc] = addv[rc] = 0;
setv[o] = -1;
}
if (addv[o] > 0) {
addv[lc] += addv[o];
addv[rc] += addv[o];
addv[o] = 0;
}
}
void maintain(int o, int L, int R) {
int lc = 2*o, rc = 2*o+1;
sumv[o] = minv[o] = maxv[o] = 0;
if (setv[o] >= 0) {
minv[o] = maxv[o] = setv[o] + addv[o];
sumv[o] = (setv[o]+addv[o]) * (R-L+1);
//addv[o] = 0;
return;
}
if (R > L) {
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
sumv[o] = sumv[lc] + sumv[rc];
}
minv[o] += addv[o];
maxv[o] += addv[o];
sumv[o] += (R-L+1)*addv[o];
}
void build(int o, int L, int R) {
if (L == R) {
minv[o] = 0;//arr[L];
maxv[o] = 0;//arr[L];
sumv[o] = 0;//arr[L];
addv[o] = 0;
setv[o] = -1;
} else {
int M = L + (R-L)/2;
int lc = 2*o, rc = 2*o+1;
build(lc, L, M);
build(rc, M+1, R);
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
sumv[o] = sumv[lc] + sumv[rc];
addv[o] = 0;
setv[o] = -1;
}
}
};
IntervalTree tree[21];
int main()
{
int r, c, m;
int op;
int x1, y1, x2, y2, v;
while(scanf("%d%d%d",&r,&c,&m) != EOF) {
REP(i, 1, r) {
tree[i].init(c);
tree[i].build(1, 1, c);
}
F(i, m) {
scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
switch(op) {
case 1:
scanf("%d",&v);
REP(j, x1, x2)
tree[j].add(y1, y2, v);
break;
case 2:
scanf("%d",&v);
REP(j, x1, x2)
tree[j].setto(y1, y2, v);
break;
case 3:
REP(j, x1, x2)
tree[j].query(y1, y2);
int _min = INF;
int _max = -INF;
int sum = 0;
REP(j, x1, x2) {
_min = min(_min, tree[j]._min);
_max = max(_max, tree[j]._max);
sum += tree[j]._sum;
}
printf("%d %d %d\n", sum, _min, _max);
break;
}
}
}
return 0;
}
本文深入探讨了线段树的实现细节及其在解决复杂区间更新与查询问题中的应用。通过一个具体的编程示例,详细介绍了如何构建线段树、进行区间加法、设置区间值及查询区间最小值、最大值和总和的方法。
340

被折叠的 条评论
为什么被折叠?



