题解:P15945 [JOI Final 2026] 雨落三角 / Triangular Rainfall
MikotoHohenz · · 题解
[JOI Final 2026] 雨落三角 / Triangular Rainfall 题解
upd: 26-11-08 将 “找到一个从
cnblogs
思路
首先发现这道题似乎是一个扫描线问题,但是插入的图形是一个等腰三角形,并不好直接处理,尝试将三角形表达为若干矩形也是不可行的。于是不妨将所有约束写出来:对于一个被覆盖的点
这个只需要推一下小式子就能得到。第三个约束看着很棘手,不妨将这一维放到扫描线中处理。
此时对于
插入所有矩形后,可以发现所有满足天数
先考虑维护
区间推平可以使用 ODT,时间复杂度均摊为
复杂度
均摊时间复杂度:
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, k;
struct node {
int l, r;
mutable int v;
friend bool operator < (node x, node y) {
return x.l < y.l;
}
};
using ll = long long;
ll ans[N];
ll L;
ll calc(ll l, ll r, ll v) {
r = min(r, L - v - 1);
if (r < l) return 0;
ll xl = L - v - r;
ll xr = L - v - l;
return (xl + xr - 1) * (xr - xl + 1);
}
struct ODT {
set<node> odt;
int l;
ODT(int l) : l(l) {
odt.insert({0, l, l + 1});
}
auto split(int x) {
if (x > l) return odt.end();
auto it = --odt.upper_bound({x, 0, 0});
if (it->l == x) return it;
int l = it->l, r = it->r, v = it->v;
odt.erase(it);
odt.insert({l, x - 1, v});
return odt.insert({x, r, v}).first;
}
void assign(int l, int r, int x, int lev, vector<ODT> &s) {
auto itr = split(r + 1), itl = split(l), it = odt.begin();
for (it = itl; it != itr; it++) {
if (it->v > x) {
if (lev < k)
s[lev + 1].assign(it->l, it->r, it->v, lev + 1, s);
ans[lev] -= calc(it->l, it->r, it->v);
}
else {
break;
}
}
if (it != itr && lev < k)
s[lev + 1].assign(it->l, r, x, lev + 1, s);
if (it != itl) {
int R = prev(it)->r;
odt.erase(itl, it);
odt.insert({l, R, x});
ans[lev] += calc(l, R, x);
}
}
};
struct qry {
ll x, y, s;
friend bool operator < (qry x, qry y) {
return x.s > y.s;
}
};
int main() {
int l, n;
cin >> l >> n >> k;
vector<ODT> s(k + 1, ODT(l));
vector<qry> lis;
for (int i = 1; i <= n; i++) {
ll x, y, z;
cin >> x >> y >> z;
lis.push_back({x, y, x + y + z});
}
sort(lis.begin(), lis.end());
for (auto [x, y, S] : lis) {
L = S;
s[1].assign(x, l, y, 1, s);
}
for (int i = 1; i <= k; i++)
cout << ans[i] << '\n';
return 0;
}