題意: 一維數軸上有 個雷。第 個雷在位置 。 花費 的代價可以引爆第 個雷,並將區間 的範圍的雷全部引爆,引起連鎖反應而不需要額外的代價。現在又 次修改,每次修改一個雷的花費,然後詢問使得所有雷爆炸的最小花費是多少。
題解: 建一棵線段樹,每個父親節點向左右兒子分別連一條有向邊。然後枚舉每一個雷,從 所在的葉子節點,向 對應的節點連邊,tarjan 求一次 scc。刪掉所有可以從含有葉子節點的 scc 到達的 scc,剩下的每個包含葉子的 scc 的最小值之和就是答案。修改可以每個 scc 維護一個 multiset。時間複雜度 。
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int maxm = maxn << 2;
vector<int> g[maxm], h[maxm];
int dfn[maxm], low[maxm], belong[maxm], scc, cnt;
bool vis[maxm];
stack<int> s;
void tarjan(int u) {
low[u] = dfn[u] = ++cnt;
s.push(u);
vis[u] = 1;
for (int v: g[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
++scc;
int v;
do {
v = s.top();
s.pop();
vis[v] = 0;
belong[v] = scc;
} while (u != v);
}
}
int id[maxn];
struct SegmentTree {
#define ls (rt<<1)
#define rs (rt<<1|1)
void build(int l, int r, int rt) {
if (l == r) {
id[l] = rt;
return;
}
int m = (l + r) / 2;
g[rt].push_back(ls);
g[rt].push_back(rs);
build(l, m, ls);
build(m+1, r, rs);
}
void query(int l, int r, int p, int L, int R, int rt) {
if (l <= L && R <= r) {
g[p].push_back(rt);
return;
}
int m = (L + R) / 2;
if (l <= m) query(l, r, p, L, m, ls);
if (r > m) query(l, r, p, m+1, R, rs);
}
} T;
struct node {
int p, r, c;
friend bool operator< (const node& x, const node& y) {
return x.p < y.p;
}
} a[maxn];
int rk[maxn], in[maxm];
vector<pair<int, int>> dx;
multiset<int> ms[maxm];
bool ins[maxm];
int main() {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &a[i].p, &a[i].r, &a[i].c);
dx.push_back({a[i].p, i});
}
sort(dx.begin(), dx.end());
T.build(1, n, 1);
for (int i = 1; i <= n; i++) {
rk[i] = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p, i)) - dx.begin() + 1;
int l = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p - a[i].r, 0)) - dx.begin() + 1;
int r = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p + a[i].r + 1, 0)) - dx.begin();
T.query(l, r, id[rk[i]], 1, n, 1);
}
int m = 4 * n;
for (int i = 1; i <= m; i++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= scc; i++) vis[i] = 0;
for (int i = 1; i <= n; i++) {
vis[belong[id[rk[i]]]] = 1;
ms[belong[id[rk[i]]]].insert(a[i].c);
}
queue<int> Q;
for (int u = 1; u <= m; u++) {
for (int v: g[u]) {
if (belong[u] != belong[v]) {
h[belong[u]].push_back(belong[v]);
if (vis[belong[u]]) {
++in[belong[v]];
if (!vis[belong[v]] && !ins[belong[v]]) {
Q.push(belong[v]);
ins[v] = 1;
}
}
}
}
}
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int v: h[u]) {
in[v] += in[u];
if (!ins[v]) {
Q.push(v);
ins[v] = 1;
}
}
ins[u] = 0;
}
ll sum = 0;
for (int i = 1; i <= scc; i++) {
if (vis[i] && in[i] == 0) sum += *ms[i].begin();
}
while (q--) {
int x, y;
scanf("%d%d", &x, &y);
if (!in[belong[id[rk[x]]]]) {
sum -= *ms[belong[id[rk[x]]]].begin();
auto it = ms[belong[id[rk[x]]]].find(a[x].c);
ms[belong[id[rk[x]]]].erase(it);
ms[belong[id[rk[x]]]].insert(y);
sum += *ms[belong[id[rk[x]]]].begin();
a[x].c = y;
}
printf("%lld\n", sum);
}
return 0;
}