题目大意

对于一个区间 [li,ri][l_i,r_i],计算矿石在这个区间上的检验值 yiy_i

yi=j=liri[wjW]×j=liri[wjW]vj y_i=\sum_{j=l_i}^{r_i}[w_j \geqslant W] \times \sum_{j=l_i}^{r_i}[w_j \geqslant W]v_j

记检验结果为 y=yiy=\sum y_i,对于给定的 ss,求 ys|y-s| 的最小值。

分析

注意到 y(w)y(w) 是关于 WW 的递减函数,对 ww[wmin,wmax][w_{\min},w_{\max}] 上进行二分。

const ll MN = 2e5 + 10;

ll vv[MN], ww[MN], li[MN], ri[MN], f1[MN], f2[MN];

ll n, m, s;

int main() {
	n = rr(), m = rr(), s = rr();
	ll minw = 0x3f3f3f3f, maxw = 0;
	f1[0] = f2[0] = 0;
	for (ll i = 1; i <= n; i++) {
		ww[i] = rr(), vv[i] = rr();
		maxw = max(ww[i], maxw);
		minw = min(ww[i], minw);
	}
	for (ll i = 1; i <= m; i++) {
		li[i] = rr(), ri[i] = rr();
	}
	ll l = minw, r = maxw + 1;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (sum(mid) <= s)
			r = mid;
		else
			l = mid + 1;
	}
	ll rst = min(sum(l - 1) - s, s - sum(l));
	printf("%lld", rst);
	return 0;
}

区间求和可以用前缀和优化。

ll f1[MN], f2[MN];

ll sum(ll w) {
	for (ll i = 1; i <= n; i++) {
		ll f = ww[i] >= w;
		f1[i] = f1[i - 1] + f;
		f2[i] = f2[i - 1] + f * vv[i];
	}
	ll sum = 0;
	for (ll k = 1; k <= m; k++) {
		ll l = li[k], r = ri[k];
		sum += (f1[r] - f1[l - 1]) * (f2[r] - f2[l - 1]);
	}
	return sum;
}