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;
}
posted @ 2022-08-08 05:08  览遍千秋  阅读(118)  评论(0编辑  收藏  举报