51nod 3071 线段树练习2
题目
你需要维护一个长为 n 的序列,支持 m 个操作:
- 区间修改为一个数
- 查询一个区间中的最大子段和,即和最大的子区间的值
数据范围:
对于 30% 的数据:n≤8,m≤10。
对于 70% 的数据:n≤1000,m≤10000。
对于 100% 的数据:1≤n, m≤100000。
保证任意时刻数列中任意元素的和在int范围内。
输入格式:
第一行包含两个整数 n, m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1 l r k
:将区间 [l, r] 内每个数都变成 k。2 l r
:输出区间 [l, r] 内的最大子段和。
输出格式:
输出包含若干行整数,即为所有操作 2 的结果。
输入样例:
5 3
1 -2 3 -4 5
1 1 2 1
2 2 3
2 4 5
输出样例:
4
5
思路
主要分情况讨论。
e.g.左儿子开始的最大子段和,要和左儿子的和加上右儿子从左开始的最大子段和比较。
因为要把值修改成k而不是加k所以简单地修改t[p].sum = len§ * k;
代码
#include <iostream>
#define lp p << 1
#define rp p << 1 | 1
using namespace std;
const int maxn = 1e5 + 5;
int n;
int m;
int a[maxn];
struct segtree {
int l;
int r;
int tag;
int sum;
int maxL;
int maxR;
int maxn;
int lazy;
} t[maxn << 2];
int len(int p) {
return t[p].r - t[p].l + 1;
}
void brush(int p, int k) {
t[p].maxL = t[p].maxR = t[p].maxn = t[p].sum = len(p) * k;
t[p].lazy = k;t[p].tag = 1;
}
void update(int p) {//分类讨论
t[p].sum = t[lp].sum + t[rp].sum;
t[p].maxL = max(t[lp].maxL, t[lp].sum + t[rp].maxL);
t[p].maxR = max(t[rp].maxR, t[rp].sum + t[lp].maxR);
t[p].maxn = max(max(t[lp].maxn, t[rp].maxn), t[lp].maxR + t[rp].maxL);
}
void push_down(int p) {
brush(lp, t[p].lazy);
brush(rp, t[p].lazy);
t[p].lazy = 0;t[p].tag = 0;
}
void build(int p, int l, int r) {
t[p].l = l;
t[p].r = r;
if (l == r) {
t[p].maxL = t[p].maxR = t[p].sum = t[p].maxn = a[l];
return;
}
int mid = l + r >> 1;
build(lp, l, mid);
build(rp, mid + 1, r);
update(p);
}
void change(int p, int l, int r, int k) {
if (t[p].l >= l and t[p].r <= r) {
brush(p, k);
return;
}
int mid = t[p].l + t[p].r >> 1;
if (t[p].tag) push_down(p);
if (l <= mid)
change(lp, l, r, k);
if (r > mid)
change(rp, l, r, k);
update(p);
}
segtree query(int p, int l, int r) {
if (t[p].l >= l and t[p].r <= r) {
return t[p];
}
segtree T, f1, f2;
T.sum = 0;
if (t[p].tag) push_down(p);
int mid = t[p].l + t[p].r >> 1;
if (l > mid) T = query(rp, l, r);
if (r <= mid) T = query(lp, l, r);
if (l <= mid and r > mid) {
f1 = query(lp, l, r);
f2 = query(rp, l, r);
T.maxn = max(max(f1.maxn, f2.maxn), f1.maxR + f2.maxL);
T.maxL = max(f1.maxL, f1.sum + f2.maxL);
T.maxR = max(f2.maxR, f2.sum + f1.maxR);
T.sum = f1.sum + f2.sum;
}
return T;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
build(1, 1, n);
for (int i = 1; i <= m; i++) {
int op;
cin >> op;
if (op == 1) {
int l, r, k;
cin >> l >> r >> k;
change(1, l, r, k);
}
else {
int l, r;
cin >> l >> r;
segtree ans = query(1, l, r);
if (ans.maxn < 0)
cout << 0 << endl;
else cout << ans.maxn << endl;
}
}
return 0;
}