CF1710B Rain 差分+数学分析
题意简述
给出若干个雨中心 \(x_i\) 与降雨强度 \(p_i\)。
对于每场雨 \(x,p\),对位置 \(i\) 积水的贡献为 \(\max \{0, |x-i|+p \}\)
任意一个位置积水大于 \(m\) 就会发洪水,问抹去一场降雨,是否不会发洪水。
问题分析
首先,发洪水的地方一定是某个降雨中心。
本质上,每个位置的积水深度是若干个绝对值函数 \(f(x)=|x-x_i|\) 叠加的结果。容易知道类似的函数在零点取到极值。
可以通过离散化,将值域缩小到 \(n\)。
维护两个差分数组:斜率和截距,可以算出每个位置的积水量。
如果一个降水中心 \(i\),原来的积水量为 \(R_i>m\),去掉降雨 \(k\) 后积水量不超过 \(m\),则有 \(R_i - |x_j-x_i| - p_j \le m\)。
这里不处理 \(\max\) 的原因是:若题目中 \(\max\) 的式子在这里取零,即有 \(R_i \le m\),与 \(R_i > m\) 矛盾,故题目中的式子在这里 \(>0\)。
拆开绝对值有:
\[\begin{cases} R_i - x_j + x_i - p_j \le m \\ R_i - x_i + x_j - p_j \le m \end{cases}
\]
移项,有
\[\begin{cases} R_i + x_i \le x_j + p_j +m \\ R_i - x_i \le -x_j + p_j + m \end{cases}
\]
维护 \(R_i+x_i\) 和 \(R_i-x_i\) 的最大值即可。
一个注意点:多测清空时,差分数组要清到 \(n+1\) 的位置。
Codes
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long LL;
template < typename Tp >
void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
const int maxn = 200000 + 7;
int T, n, m;
struct rain {
int x, p, id;
bool ans;
}a[maxn];
void Init(void) {
read(T);
}
bool cmp(rain a, rain b) {
return a.x == b.x ? a.p < b.p : a.x < b.x;
}
bool comp(rain a, rain b) {
return a.id < b.id;
}
int sk[maxn], sb[maxn], r[maxn];
int lfind(rain t) {
int l = 1, r = n, mid, res = n;
while(l <= r) {
mid = ((l + r) >> 1);
if(a[mid].x >= t.x - t.p) res = mid, r = mid - 1;
else l = mid + 1;
}
return res;
}
int rfind(rain t) {
int l = 1, r = n, mid, res = 1;
while(l <= r) {
mid = ((l + r) >> 1);
if(a[mid].x <= t.x + t.p) res = mid, l = mid + 1;
else r = mid - 1;
}
return res;
}
void Work(void) {
while(T--) {
for(int i = 1; i <= n + 1; i++) {
sb[i] = sk[i] = r[i] = 0;
// a[i].x = a[i].p = a[i].id = a[i].ans = 0;
}
read(n); read(m);
for(int i = 1; i <= n; i++) {
read(a[i].x); read(a[i].p);
a[i].id = i;
}
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++) {
int lb = lfind(a[i]), rb = rfind(a[i]);
sk[lb]++, sk[i + 1] -= 2, sk[rb + 1]++;
sb[lb] += a[i].p - a[i].x;
sb[i + 1] -= a[i].p - a[i].x;
sb[i + 1] += a[i].p + a[i].x;
sb[rb + 1] -= a[i].p + a[i].x;
}
for(int i = 1; i <= n; i++) {
sk[i] += sk[i - 1];
sb[i] += sb[i - 1];
r[i] = sb[i] + sk[i] * a[i].x;
// cout << r[i] << " ";
}
int mx1 = -0x3f3f3f3f3f3f3f3fll, mx2 = -0x3f3f3f3f3f3f3f3fll;
for(int i = 1; i <= n; i++) {
if(r[i] > m) mx1 = max(mx1, r[i] - a[i].x);
if(r[i] > m) mx2 = max(mx2, r[i] + a[i].x);
}
for(int i = 1; i <= n; i++) {
if(a[i].p - a[i].x + m >= mx1 && a[i].x + a[i].p + m >= mx2) a[i].ans = true;
else a[i].ans = false;
}
sort(a + 1, a + n + 1, comp);
for(int i = 1; i <= n; i++) printf("%d", a[i].ans);
puts("");
}
}
signed main(void) {
Init();
Work();
return 0;
}