发现cf上竟然有这套题…
以及发现coach mode的提交不算在submission里面,奥妙重重
coach mode真香!D不想写,翻了翻其他人代码,收获一个看上去非常优雅的分数类板子。
这个E好像挺水的…
线段树区间合并的做法什么时候补一下吧(什么时候 等我学会线段树
题意
数轴上有一些住着人的洞窟,有一个人试图用m台CD机播放摇滚音乐来打扰洞窟里的住民。每台CD机可以影响的范围为l。CD机的主人会移动一台CD机。每次移动后,询问有多少个洞窟会受到音乐的影响。
解法
由于区间等长,把区间中点扔进set里,每次修改找前驱和后继查询一下受影响的点有几个,删点,查询一下修改后位置前驱后继看看受影响的点有几个,加点。维护答案。
#include <iostream>
#include <set>
#include <algorithm>
const int maxn = 500000+7;
int n, m, d, l;
int x[maxn];
std::set<int> z;
int p, r;
int zz;
int main(int argc, char *argv[]) {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cin >> n >> m >> d >> l;
x[1] = 0;
for (int i = 2; i <= n; i++) {
std::cin >> x[i];
}
for (int i = 0; i < m; i++) {
std::cin >> zz;
z.insert(zz);
}
z.insert(-1000000007);
z.insert(2000000007);
int ans = 0;
for (int i = 1; i <= n; i++) {
auto it1 = z.lower_bound(x[i]);
auto it2 = it1;
it2--;
if (std::abs(*it1-x[i]) <= l || std::abs(*it2-x[i]) <= l) {
ans++;
}
}
std::cout << ans << '\n';
int left, right, ll, rr;
for (int i = 0; i < d; i++) {
std::cin >> p >> r;
auto it1 = z.lower_bound(p);
auto it2 = it1;
it1++;
it2--;
left = std::max(*it2+l+1, p-l);
right = std::min(*it1-l-1, p+l);
ll = std::lower_bound(x+1, x+n+1, left)-(x+1);
rr = std::lower_bound(x+1, x+n+1, right+1)-(x+1);
ans -= std::max(0, rr-ll);
z.erase(p);
auto it3 = z.lower_bound(r);
auto it4 = it3;
it4--;
left = std::max(*it4+l+1, r-l);
right = std::min(*it3-l-1, r+l);
ll = std::lower_bound(x+1, x+n+1, left)-(x+1);
rr = std::lower_bound(x+1, x+n+1, right+1)-(x+1);
ans += std::max(0, rr-ll);
std::cout << ans << '\n';
z.insert(r);
}
}