目录
单点修改+区间查询
线段树1(最小值+出现次数)
题解:
需使用数据用 info 封装起来,便于修改维护,运算符 + 重载
seg[N]记录路线段树节点
update(id):id编号的子树发生了变化,所以更新id这个节点的信息,build 和 change 中需要 update 向上更新(建完左右子树后)
change:单点修改 a[pos]->val
query:[ l , r ]区间查询
根据需要修改info,+,update,build和change中队seg[id]
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5+5;
int n, q, a[N];
struct info {
int minv, mincut;
};
info operator+(const info& a, const info& b) {
info x;
if (a.minv < b.minv)x = a;
else if (b.minv < a.minv)x = b;
else x.minv = a.minv, x.mincut = a.mincut + b.mincut;
return x;
}
struct node {
info val;
}seg[N * 4];
void update(int id) {//向上更新
seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r) {//建树
if (l == r) {
seg[id] = { a[l],1 };
return;
}int m = (l + r) / 2;
build(lson);
build(rson);
update(id);//!
}
void change(int id, int l, int r, int pos, int val) {//单点修改
if (l == r) {
seg[id].val = {val,1};
return;
}
int m = (l + r) / 2;
if (pos<=m) change(lson, pos, val);
else change(rson, pos, val);
update(id);//!
}
info query(int id, int l, int r, int ql, int qr) {//区间查询
if (ql == l && qr == r) {
return seg[id].val;
}int m = (l + r) / 2;
if (qr <= m)return query(lson, ql, qr);
else if (ql > m)return query(rson, ql, qr);
else return query(lson, ql, m)
+ query(rson, m+1, qr);
}
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
while (q--) {
int tx; scanf("%d", &tx);
if (tx == 1) {
int x, d; scanf("%d%d", &x, &d);
change(1, 1, n, x, d);
}
else {
int l, r; scanf("%d%d", &l, &r);
info ans = query(1, 1, n, l, r);
printf("%d %d\n", ans.minv, ans.mincut);
}
}
return 0;
}
线段树2(最大子段和)
题解:
a[ i ]可能为负数,则区间前缀和或后缀和可能大于区间总和
mss: max segment sum //区间最大子段和
mpre : max prefix //最大前缀和
msuf : max sufix //最大后缀和
s : sum //区间和(此题未用到)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5 + 5;
int n, q, a[N];
struct info {
ll mss, mpre, msuf, s;
info() {}
info(int val) :mss(val), mpre(val), msuf(val), s(val) {}
};
info operator + (const info& l, const info& r) {
info a;
a.mss = max({ l.mss, r.mss, l.msuf + r.mpre });
a.mpre = max(l.mpre, l.s + r.mpre);
a.msuf = max(r.msuf, r.s + l.msuf);
a.s = l.s + r.s;
return a;
}
struct node {
info val;
}seg[N * 4];
void update(int id) {
seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r) {
if (l == r) {
seg[id].val = info(a[l]);
return;
}
int m = (l + r) / 2;
build(lson);
build(rson);
update(id);//!
}
void change(int id, int l, int r, int pos, int val) {
if (l == r) {
seg[id].val = info(val);
return;
}
int m = (l + r) / 2;
if (pos <= m) change(lson, pos, val);
else change(rson, pos, val);
update(id);//!
}
info query(int id, int l, int r, int ql, int qr) {
if (ql == l && qr == r) {
return seg[id].val;
}
int m = (l + r) / 2;
if (qr <= m) return query(lson, ql, qr);
else if (ql > m) return query(rson, ql, qr);
else return query(lson, ql, m) +
query(rson, m + 1, qr);
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
build(1, 1, n);
while (q--) {
int ty; scanf("%d", &ty);
if (ty == 1) {
int pos, val; scanf("%d %d", &pos, &val);
change(1, 1, n, pos, val);
}
else {
int l, r; scanf("%d %d", &l, &r);
info ans = query(1, 1, n, l, r);
printf("%lld\n", ans.mss);
}
}
return 0;
}
区间修改+区间查询
线段树打标记1(最大值)
题解:
settag(id):给id这个节点打标记,同时节点的信息发生变化
update(id):id编号的子树发生了变化,所以更新id这个节点的信息,build 和 modify 中需要 update 向上更新(建完左右子树后)
pushdown(id):将id节点的标记下传给子节点,区间修改 modify 和区间查询 query 中传递到 子节点前进行
modify:[ l , r ]区间修改
注意tag要开ll ,因为标记可能叠加(不着急传到子节点)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5 + 5;
int n, q, a[N];
struct node {
ll t, val;
}seg[N * 4];
void update(int id) {
seg[id].val = max(seg[id * 2].val , seg[id * 2 + 1].val);
}
void settag(int id, ll t) {
seg[id].val += t;
seg[id].t += t;
}
void pushdown(int id) {
if (seg[id].t) {
settag(id * 2, seg[id].t);
settag(id * 2 + 1, seg[id].t);
seg[id].t = 0;
}
}
void build(int id, int l, int r) {
if (l == r) {
seg[id].val = a[l];
return;
}
int m = (l + r) / 2;
build(lson);
build(rson);
update(id);//!
}
void modify(int id, int l, int r, int ql, int qr,int t) {
if (ql==l&&qr == r) {
settag(id, t);
return;
}pushdown(id);
int m = (l + r) / 2;
if (qr <= m) modify(lson, ql, qr, t);
else if (ql > m)modify(rson, ql, qr, t);
else modify(lson, ql, m, t),
modify(rson, m + 1, qr, t);
update(id);//!
}
ll query(int id, int l, int r, int ql, int qr) {
if (ql == l && qr == r) {
return seg[id].val;
}pushdown(id);
int m = (l + r) / 2;
if (qr <= m) return query(lson, ql, qr);
else if (ql > m) return query(rson, ql, qr);
else return max(query(lson, ql, m) ,
query(rson, m + 1, qr));
//update(id);
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
build(1, 1, n);
while (q--) {
int ty; scanf("%d", &ty);
if (ty == 1) {
int l, r, t;
scanf("%d%d%d", &l, &r, &t);
modify(1, 1, n, l, r, t);
}
else {
int l, r; scanf("%d%d", &l, &r);
ll ans=query(1, 1, n, l, r);
printf("%lld\n", ans);
}
}
return 0;
}
线段树打标记2(子段和取mod)
题解:
按常理来说,要有多个标记。但是多个标记太麻烦了,而且还要考虑先后顺序。所以就萌发出一种合并这3个标记的想法,在根据合并后的标记对区间和进行更新
struct tag { ll mul, add; };
- +d -> v*1+d {1,d}
- *d -> v*d+0 {d,0}
- 变成d -> v*0+d {0, d}
起始时,tag的每个tag的初始状态为(1,0),即v*1+0
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2E5 + 5;
int n, q, a[N];
const int mod = 1e9 + 7;
struct tag {
ll mul, add;
};
tag operator + (const tag& t1, const tag& t2) {
// (mul1 + add1) * mul2 + add2;
return { t1.mul * t2.mul % mod, (t1.add * t2.mul % mod + t2.add) % mod };
}
struct node {
tag t;
ll val;
int sz;
}seg[N * 4];
void update(int id) {
seg[id].val = (seg[id * 2].val + seg[id * 2 + 1].val) % mod;
}
void build(int id, int l, int r) {
seg[id].t = (tag){ 1, 0 };
seg[id].sz = r - l + 1;
if (l == r) {
seg[id].val = a[l];
}
else {
int m = (l + r) / 2;
build(lson);
build(rson);
update(id);
}
}
void settag(int id, tag t) {
seg[id].val = seg[id].val * t.mul % mod + seg[id].sz * t.add % mod;
seg[id].t = seg[id].t + t;
}
void pushdown(int id) {
if (seg[id].t.mul != 1 || seg[id].t.add != 0) {
settag(id * 2, seg[id].t);
settag(id * 2 + 1, seg[id].t);
seg[id].t.mul = 1;
seg[id].t.add = 0;
}
}
void modify(int id, int l, int r, int ql, int qr, tag t) {
if (l == ql && r == qr) {
settag(id, t);
return;
}
pushdown(id);
int m = (l + r) / 2;
if (qr <= m) modify(lson, ql, qr, t);
else if (ql > m) modify(rson, ql, qr, t);
else modify(lson, ql, m, t),
modify(rson, m + 1, qr, t);
update(id);
}
ll query(int id, int l, int r, int ql, int qr) {
if (l == ql && r == qr) {
return seg[id].val;
}
pushdown(id);
int m = (l + r) / 2;
if (qr <= m) return query(lson, ql, qr);
else if (ql > m) return query(rson, ql, qr);
else return (query(lson, ql, m) +
query(rson, m + 1, qr)) % mod;
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
build(1, 1, n);
while (q--) {
int ty; scanf("%d", &ty);
if (ty <= 3) {
int l, r, d;
scanf("%d %d %d", &l, &r, &d);
if (ty == 1) modify(1, 1, n, l, r, (tag) { 1, d });
else if (ty == 2) modify(1, 1, n, l, r, (tag) { d, 0 });
else modify(1, 1, n, l, r, (tag) { 0, d });
}
else {
int l, r; scanf("%d %d", &l, &r);
printf("%lld\n", query(1, 1, n, l, r));
}
}
return 0;
}