P12845 [蓝桥杯 2025 国 A] 连锁反应 题解
lyhr31415926 · · 题解
将炸弹按位置排序。先预处理出每个炸弹引爆后能影响到的最 左/右 侧的炸弹。以左侧为例:
设
相同的,设
处理完左右两侧后,再做一个 DP。设
所有的区间查询、单点修改都用线段树维护。
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar();
}
return x * f;
}
struct SegmentTree {
int mn[800005], mx[800005];
void pushup(int p) {
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
return;
}
void build(int p, int l, int r) {
mn[p] = 1e15;
mx[p] = -1e15;
if(l == r) {
return;
}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
return;
}
void upd(int p, int l, int r, int k, int x) {
if(l == r) {
mn[p] = min(mn[p], x);
mx[p] = max(mx[p], x);
return;
}
int mid = l + r >> 1;
if(k <= mid) upd(p << 1, l, mid, k, x);
else upd(p << 1 | 1, mid + 1, r, k, x);
pushup(p);
return;
}
int querymn(int p, int l, int r, int L, int R) {
if(R < L) return 1e15;
if(L <= l && r <= R) {
return mn[p];
}
int mid = l + r >> 1;
if(L > mid) return querymn(p << 1 | 1, mid + 1, r, L, R);
if(R <= mid) return querymn(p << 1, l, mid, L, R);
return min(querymn(p << 1, l, mid, L, R), querymn(p << 1 | 1, mid + 1, r, L, R));
}
int querymx(int p, int l, int r, int L, int R) {
if(R < L) return 1e15;
if(L <= l && r <= R) {
return mx[p];
}
int mid = l + r >> 1;
if(L > mid) return querymx(p << 1 | 1, mid + 1, r, L, R);
if(R <= mid) return querymx(p << 1, l, mid, L, R);
return max(querymx(p << 1, l, mid, L, R), querymx(p << 1 | 1, mid + 1, r, L, R));
}
}G, H, F;
struct node {
int p, l, r;
}a[200005];
int n, g[200005], h[200005], f[200005], ans = 1e15;
inline int queryup(int x) {
int l = 1, r = n, res = -1;
while(l <= r) {
int mid = l + r >> 1;
if(a[mid].p >= x) {
res = mid;
r = mid - 1;
}
else l = mid + 1;
}
return res;
}
inline int querydn(int x) {
int l = 1, r = n, res = -1;
while(l <= r) {
int mid = l + r >> 1;
if(a[mid].p <= x) {
res = mid;
l = mid + 1;
}
else r = mid - 1;
}
return res;
}
bool cmp(node x, node y) {
return x.p < y.p;
}
signed main() {
n = read();
for(int i = 1; i <= n; ++i) {
a[i].p = read(); a[i].l = read(); a[i].r = read();
}
G.build(1, 1, n); H.build(1, 1, n); F.build(1, 0, n);
g[0] = 0, h[0] = 0;
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; ++i) {
int id = queryup(a[i].p - a[i].l);
if(id == -1 || id >= i) g[i] = 1;
else {
g[i] = max(1ll, i - G.querymn(1, 1, n, id, i - 1));
}
G.upd(1, 1, n, i, i - g[i]);
}
for(int i = n; i >= 1; --i) {
int id = querydn(a[i].p + a[i].r);
if(id == -1 || id <= i) h[i] = 1;
else {
h[i] = max(1ll, H.querymx(1, 1, n, i + 1, id) - i);
}
H.upd(1, 1, n, i, h[i] + i);
}
f[0] = 0;
F.upd(1, 0, n, 0, 0);
for(int i = 1; i <= n; ++i) {
f[i] = F.querymn(1, 0, n, i - g[i], n) + 1;
F.upd(1, 0, n, i + h[i] - 1, f[i]);
}
for(int i = 1; i <= n; ++i) {
if(i + h[i] - 1 == n) {
ans = min(ans, f[i]);
}
}
cout<<ans;
return 0;
}