题解:CF500E New Year Domino
提供一个回滚莫队解法
首先有个显而易见的结论,若
考虑寻找答案的过程,记
观察到只有前缀最大值是对答案有贡献的,考虑将这些前缀最大值所在点加入一个双端队列中,设双端队列末尾为
(代码中用数组模拟双端队列,
if (s[que[back]]<s[R+1]) que[++back]=R+1,ans+=calc(back);
再考虑向前拓展会发生什么情况,发现可以用类似单调队列的方法,也就是不断把队列前端
while (front<=back&&s[que[front]]<s[L-1]) {
if (front<back)//判有没有可删除贡献
ans-=calc(front+1);
front++;
}
que[--front]=L-1;
if (front<back) ans+=calc(front+1);
感觉不可删除两端,所以用回滚莫队维护这一过程。
然后注意到向前扩展需要均摊后时间复杂度才是对的,所以我们回滚的时候若撤销向前扩展的操作,时间复杂度可能出错,所以我们以右端点所在块为第一关键字排序,左端点为第二关键字排序,每次撤销向后扩展的操作即可。
时间复杂度
给出代码
#include <bits/stdc++.h>
using namespace std;
inline long long read(void) {
long long x = 0, f = 1;
char c = getchar();
while (c > '9' || c < '0') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - 48, c = getchar();
return x * f;
}
struct node {
long long l, r, id;
};
const int k = 450;
long long n, q, cnt, nl, nr, l[200005], r[200005], bl[1000], qwq[200005], ans[200005], que[500005], h, t;
vector<node> query[1000];
bool cmp (node x, node y) {
return x. l > y. l;
}
int main(void) {
n = read();
for (int i = 1; i <= n; i++) qwq[i] = (i - 1) / k + 1, bl[qwq[i]] = bl[qwq[i]] ? bl[qwq[i]] : i;
for (int i = 1; i <= n; i++) l[i] = read(), r[i] = l[i] + read();
q = read();
for (int i = 1; i <= q; i++) {
nl = read(), nr = read();
if (qwq[nl] == qwq[nr]) {
h = 0;
for (int j = nl; j <= nr; j++) {
if (!h) que[++h] = j;
else if (r[j] > r[que[h]]) que[++h] = j, ans[i] += max(l[que[h]] - r[que[h - 1]], 0ll);
}
} else query[qwq[nr]]. push_back({nl, nr, i});
}
for (int i = 1; i <= qwq[n]; i++) {
if (query[i]. empty()) continue;
sort(query[i]. begin(), query[i]. end(), cmp);
long long p = bl[i], s = 0;
h = 250000, t = 249999;
for (auto [ql, qr, id] : query[i]) {
while (p > ql) {
p--;
while (h <= t && r[que[h]] < r[p]) {
if (h < t) s -= max(0ll, l[que[h + 1]] - r[que[h]]);
h++;
}
que[--h] = p;
if (h < t) s += max(0ll, l[que[h + 1]] - r[que[h]]);
}
long long _t = t, _s = s;
for (int j = bl[i]; j <= qr; j++) if (r[que[t]] < r[j]) que[++t] = j, s += max(0ll, l[que[t]] - r[que[t - 1]]);
ans[id] = s + max(0ll, l[qr] - r[que[t]]);
t = _t, s = _s;
}
}
for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
return 0;
}