专题:线段树
最大数
题意:
添加操作:向序列后添加一个数,序列长度变成 n+1;
询问操作:询问这个序列中最后 L 个数中最大的数是多少
强制在线
//
// Created by vv123 on 2022/9/5.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
struct SegmentTree {
int mx[N << 2];
SegmentTree() {
memset(mx, 0, sizeof mx);
}
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
void pushup(int u) {
mx[u] = max(mx[ls], mx[rs]);
}
void upd(int pos, int l, int r, int u, int val) {
//printf("%d %d %d\n", l, r, u);
if (l == pos && r == pos) { mx[u] = val; return; }
if (pos <= mid) upd(pos, l, mid, ls, val);
else upd(pos, mid + 1, r, rs, val);
pushup(u);
}
int ask(int s, int t, int l, int r, int u) {
if (ain) return mx[u];
int res = 0;
if (lin) res = max(res, ask(s, t, l, mid, ls));
if (rin) res = max(res, ask(s, t, mid + 1, r, rs));
return res;
}
} tr;
int m, p;
signed main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> m >> p;
int lastans = 0, n = 0;
for (int i = 1; i <= m; i++) {
string op; int x;
cin >> op >> x;
if (op == "A") {
tr.upd(n + 1, 1, m, 1, (x + lastans) % p);
n++;
} else {
lastans = tr.ask(n - x + 1, n, 1, m, 1);
cout << lastans << "\n";
}
}
return 0;
}
单点修改,查询区间最大子段和
//
// Created by vv123 on 2022/9/9.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
const int N = 2e6 + 10;
const int inf = 0x3f3f3f3f;
int n, m, a[N];
struct node {
int sum, lmax, rmax, dat;
};
struct SegmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
int sum[N << 2], lmax[N << 2], rmax[N << 2], dat[N << 2];
void pushup(int u) {
sum[u] = sum[ls] + sum[rs];
lmax[u] = max(lmax[ls], sum[ls] + lmax[rs]);
rmax[u] = max(rmax[rs], sum[rs] + rmax[ls]);
dat[u] = max(rmax[ls] + lmax[rs], max(dat[ls], dat[rs]));
}
void build(int l, int r, int u) {
if (l == r) {
sum[u] = lmax[u] = rmax[u] = dat[u] = a[l];
return;
}
build(l, mid, ls);
build(mid + 1, r, rs);
pushup(u);
}
node ask(int s, int t, int l, int r, int u) {
if (ain) return {sum[u], lmax[u], rmax[u], dat[u]};
node ansl = {-inf, -inf, -inf, -inf};
node ansr = {-inf, -inf, -inf, -inf};
node ans = {0, -inf, -inf, -inf};
if (lin) ansl = ask(s, t, l, mid, ls), ans.sum += ansl.sum;
if (rin) ansr = ask(s, t, mid + 1, r, rs), ans.sum += ansr.sum;
ans.dat = max(ansl.rmax + ansr.lmax, max(ansl.dat, ansr.dat));
ans.lmax = max(ansl.lmax, ansl.sum + ansr.lmax);
ans.rmax = max(ansr.rmax, ansr.sum + ansl.rmax);
if (!lin) ans.lmax = max(ans.lmax, ansr.lmax);
if (!rin) ans.rmax = max(ans.rmax, ansl.rmax);
return ans;
}
void upd(int pos, int l, int r, int u, int val) {
if (l == r) {
sum[u] = lmax[u] = rmax[u] = dat[u] = val;
return;
}
if (pos <= mid) upd(pos, l, mid, ls, val);
else upd(pos, mid + 1, r, rs, val);
pushup(u);
}
} tr;
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
tr.build(1, n, 1);
while (m--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 1) {
if (x > y) swap(x, y);
cout << tr.ask(x, y, 1, n, 1).dat << "\n";
} else {
tr.upd(x, 1, n, 1, y);
}
}
}
signed main() {
int T = 1; //cin >> T;
while (T--) solve();
return 0;
}
区间修改,查询区间GCD
这个问题可以差分单点做。
//
// Created by vv123 on 2022/9/9.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
int n, m, a[N], b[N], t[N];
void add(int i, int x) {
for (; i <= n; i += i & -i)
t[i] += x;
}
int sum(int i) {
int res = 0;
for (; i; i -= i & -i)
res += t[i];
return res;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
struct SegmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
int g[N << 2];
void pushup(int u) {
g[u] = gcd(g[ls], g[rs]);
}
void build(int l, int r, int u) {
if (l == r) {
g[u] = b[l];
return;
}
build(l, mid, ls);
build(mid + 1, r, rs);
pushup(u);
}
int ask(int s, int t, int l, int r, int u) {
if (ain) return g[u];
int res = 0;
if (lin) res = gcd(res, ask(s, t, l, mid, ls));
if (rin) res = gcd(res, ask(s, t, mid + 1, r, rs));
return abs(res);
}
void add(int pos, int l, int r, int u, int val) {
if (l == r) {
g[u] += val;
return;
}
if (pos <= mid) add(pos, l, mid, ls, val);
else add(pos, mid + 1, r, rs, val);
pushup(u);
}
} tr;
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i] - a[i - 1];
add(i, b[i]);
}
tr.build(1, n, 1);
while (m--) {
string op; int l, r, d;
cin >> op >> l >> r;
if (op == "Q") {
cout << gcd(sum(l), tr.ask(l + 1, r, 1, n, 1)) << "\n";
} else {
cin >> d;
add(l, d);
if (r + 1 <= n) add(r + 1, -d);
tr.add(l, 1, n, 1, d);
if (r + 1 <= n) tr.add(r + 1, 1, n, 1, -d);
}
}
}
signed main() {
int T = 1; //cin >> T;
while (T--) solve();
return 0;
}
区间加,区间求和
注意懒标记的处理
//
// Created by vv123 on 2022/8/31.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
int a[N];
struct segmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
#define len (r-l+1)
#define llen (mid-l+1)
#define rlen (r-mid)
int sum[N], laz[N];
void pushup(int u) {
sum[u] = sum[ls] + sum[rs];
}
void pushdown(int l, int r, int u) {
if (laz[u]) {
sum[ls] += laz[u] * llen;
sum[rs] += laz[u] * rlen;
laz[ls] += laz[u];
laz[rs] += laz[u];
laz[u] = 0;
}
}
void build(int l, int r, int u) {
if (l == r) { sum[u] = a[l]; return; }
build(l, mid, ls); build(mid + 1, r, rs);
pushup(u);
}
void upd(int s, int t, int l, int r, int u, int k) {
if (ain) {
sum[u] += k * len;
laz[u] += k;
return;
}
pushdown(l, r, u);
if (lin) upd(s, t, l, mid, ls, k);
if (rin) upd(s, t, mid + 1, r, rs, k);
pushup(u);
}
int ask(int s, int t, int l, int r, int u) {
int res = 0;
if (ain) return sum[u];
pushdown(l, r, u);
if (lin) res += ask(s, t, l, mid, ls);
if (rin) res += ask(s, t, mid + 1, r, rs);
return res;
}
} tr;
signed main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
tr.build(1, n, 1);
while (m--) {
string op; int l, r, x;
cin >> op;
if (op == "Q") {
cin >> l >> r;
cout << tr.ask(l, r, 1, n, 1) << "\n";
} else {
cin >> l >> r >> x;
tr.upd(l, r, 1, n, 1, x);
}
}
return 0;
}
扫描线
//
// Created by vv123 on 2022/9/9.
//
//存板子!
#include <stdio.h>
#include <iostream>
#include <algorithm>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll double
using namespace std;
const int MAXN = 1e6 + 10;
int n, cnt = 0;
ll x1, y1, x2, y2, X[MAXN << 1];
struct ScanLine {
ll l, r, h;
int mark;
// mark用于保存权值 (1 / -1)
bool operator < (const ScanLine &rhs) const {
return h < rhs.h;
}
} line[MAXN << 1];
struct SegTree {
int l, r, sum;
ll len;
// sum: 被完全覆盖的次数;
// len: 区间内被截的长度。
} tree[MAXN << 2];
void build_tree(int x, int l, int r) {
// 我觉得最不容易写错的一种建树方法
tree[x].l = l, tree[x].r = r;
tree[x].len = 0;
tree[x].sum = 0;
if(l == r)
return;
int mid = (l + r) >> 1;
build_tree(lson, l, mid);
build_tree(rson, mid + 1, r);
return;
}
void pushup(int x) {
int l = tree[x].l, r = tree[x].r;
if(tree[x].sum /* 也就是说被覆盖过 */ )
tree[x].len = X[r + 1] - X[l];
// 更新长度
else
tree[x].len = tree[lson].len + tree[rson].len;
// 合并儿子信息
}
void edit_tree(int x, ll L, ll R, int c) {
int l = tree[x].l, r = tree[x].r;
// 注意,l、r和L、R的意义完全不同
// l、r表示这个节点管辖的下标范围
// 而L、R则表示需要修改的真实区间
if(X[r + 1] <= L || R <= X[l])
return;
// 这里加等号的原因:
// 假设现在考虑 [2,5], [5,8] 两条线段,要修改 [1,5] 区间的sum
// 很明显,虽然5在这个区间内,[5,8] 却并不是我们希望修改的线段
// 所以总结一下,就加上了等号
if(L <= X[l] && X[r + 1] <= R) {
tree[x].sum += c;
pushup(x);
return;
}
edit_tree(lson, L, R, c);
edit_tree(rson, L, R, c);
pushup(x);
}
int main() {
int kase = 0;
while (scanf("%d", &n) && n) {
for(int i = 1; i <= n; i++) {
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
X[2 * i - 1] = x1, X[2 * i] = x2;
line[2 * i - 1] = (ScanLine) {x1, x2, y1, 1};
line[2 * i] = (ScanLine) {x1, x2, y2, -1};
// 一条线段含两个端点,一个矩形的上下边都需要扫描线扫过
}
n <<= 1;
// 直接把 n <<= 1 方便操作
sort(line + 1, line + n + 1);
sort(X + 1, X + n + 1);
int tot = unique(X + 1, X + n + 1) - X - 1;
// 去重最简单的方法:使用unique!(在<algorithm>库中)
build_tree(1, 1, tot - 1);
// 为什么是 tot - 1 :
// 因为右端点的对应关系已经被篡改了嘛…
// [1, tot - 1]描述的就是[X[1], X[tot]]
ll ans = 0;
for(int i = 1; i < n /* 最后一条边是不用管的 */ ; i++) {
edit_tree(1, line[i].l, line[i].r, line[i].mark);
// 先把扫描线信息导入线段树
ans += tree[1].len * (line[i + 1].h - line[i].h);
// 然后统计面积
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++kase, ans);
}
return 0;
}
区间加法和乘法,区间求和
注意多种懒标记的处理
//
// Created by vv123 on 2022/4/24.
//
#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<15,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<15],*frS=frBB,*frT=frBB;
template<typename T>
inline void read(T &x){
x=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
}
const int N = 4e5 + 10;
int mod = 998244353;
int n, m, a[N];
ll add[N], mul[N], sum[N];
#define mid (l+r>>1)
#define len (r-l+1)
#define llen (mid-l+1)
#define rlen (r-mid)
#define ls (i<<1)
#define rs (i<<1|1)
#define allin s <= l && r <= t //[s,t]与[l,r]一定有交集,只需考虑三种情况
#define lsin s <= mid
#define rsin t >= mid + 1
inline void pushup(int i) {
sum[i] = (sum[ls] + sum[rs]) % mod;
}
inline void pushdown(int l, int r, int i) {
if (mul[i] != 1) {
(mul[ls] *= mul[i]) %= mod; (mul[rs] *= mul[i]) %= mod;
(add[ls] *= mul[i]) %= mod; (add[rs] *= mul[i]) %= mod;
(sum[ls] *= mul[i]) %= mod; (sum[rs] *= mul[i]) %= mod;
mul[i] = 1;
}
if (add[i]) {
(sum[ls] += add[i] * llen) %= mod; (sum[rs] += add[i] * rlen) %= mod;
(add[ls] += add[i]) %= mod; (add[rs] += add[i]) %= mod;
add[i] = 0;
}
}
void Build(int l, int r, int i) {
mul[i] = 1;
if (l == r) { sum[i] = a[l]; return; }
Build(l, mid, ls); Build(mid + 1, r, rs);
pushup(i);
}
void Add(int s, int t, int l, int r, int i, int k) {
if (allin) {
(sum[i] += k * len) %= mod;
(add[i] += k) %= mod;
return;
}
pushdown(l, r, i);
if (lsin) Add(s, t, l, mid, ls, k);
if (rsin) Add(s, t, mid + 1, r, rs, k);
pushup(i);
}
void Mul(int s, int t, int l, int r, int i, int k) {
if (allin) {
(add[i] *= k) %= mod;
(mul[i] *= k) %= mod;
(sum[i] *= k) %= mod;
return;
}
pushdown(l, r, i);
if (lsin) Mul(s, t, l, mid, ls, k);
if (rsin) Mul(s, t, mid + 1, r, rs, k);
pushup(i);
}
ll Query(int s, int t, int l, int r, int i) {
ll res = 0;
if (allin) return sum[i];
pushdown(l, r, i);
if (lsin) (res += Query(s, t, l, mid, ls)) %= mod;
if (rsin) (res += Query(s, t, mid + 1, r, rs)) %= mod;
return res;
}
int main() {
read(n); read(mod);
for (int i = 1; i <= n; i++) read(a[i]);
Build(1, n, 1);
read(m);
while(m--) {
int op, s, t, k;
read(op); read(s); read(t);
if (op == 1) {
read(k); Mul(s, t, 1, n, 1, k);
} else if (op == 2) {
read(k); Add(s, t, 1, n, 1, k);
} else {
printf("%lld\n", Query(s, t, 1, n, 1));
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】