1. 程式人生 > 其它 >【二分】luogu_P7405 [JOI 2021 Final] 雪玉

【二分】luogu_P7405 [JOI 2021 Final] 雪玉

題意

在一條無限長的數軸上,有\(N\)個雪球,編號為\(1 \sim N\),第\(i\)個雪球在第\(A_i\)個點上。

剛開始,整條數軸覆蓋滿了雪,接下來\(Q\)天將會颳起大風,第\(j\)天的風力強度為\(W_j\),如果\(W_j\)為正數,所有雪球都朝右移動\(W_j\)個單位長度,如果\(W_j\)為負數,所有雪球都朝左移動\(-W_j\)個單位長度。
當一個區間\([a,a+1]\)被雪覆蓋時,雪球滾上去雪球的質量會加一,這一個區間裡的雪也會被清空。

剛開始每一個雪球的質量均為\(0\),而這\(Q\)天裡也沒有再下雪。
問這\(Q\)天結束後每個雪球的質量。

思路

可以發現對於相鄰兩個雪球之間的區間裡的雪一定是貢獻給了這兩個球。

那麼對於每個區間,要找出左右雪球佔的質量。

發現向左向右的最大值是具有單調性的,可以進行二分。

程式碼

#include <cstdio>
#define int long long

int n, q;
int p[200001], l[200001], r[200001], ans[200001];

void calc(int cur, int len) {
	if (l[q] + r[q] <= len) {
		ans[cur] += r[q];
		ans[cur + 1] += l[q];
		return;
	}
	int L = 1, R = q, mid;
	while (L < R) {
		int mid = L + R >> 1;
		if (l[mid] + r[mid] <= len)
			L = mid + 1;
		else
			R = mid;
	}
	if (l[L] == l[L - 1])
		ans[cur] += len - l[L], ans[cur + 1] += l[L];
	else
		ans[cur] += r[L], ans[cur + 1] += len - r[L];
}

signed main() {
	scanf("%lld %lld", &n, &q);
	for (int i = 1; i <= n; ++i)
		scanf("%lld", &p[i]);
	for (int i = 1, x, cur = 0; i <= q; ++i) {
		scanf("%lld", &x);
		cur += x;
		l[i] = l[i - 1] > -cur ? l[i - 1] : -cur;
		r[i] = r[i - 1] > cur ? r[i - 1] : cur;
	}
	ans[1] += l[q];
	ans[n] += r[q];
	for (int i = 1; i < n; ++i)
		calc(i, p[i + 1] - p[i]);
	for (int i = 1; i <= n; ++i)
		printf("%lld\n", ans[i]);
}