「解题报告」P9353 [JOI 2023 Final] Modern Machine
首先考虑一次操作干了什么,注意到我们只有在最后一次转弯后的覆盖是有意义的,那么实际上,将结果分为从左边出界和从右边出界,分别造成的修改是前缀染红与后缀染蓝。
那么考虑具体染了多少,大概手动模拟一下发现,如果在第
那么暴力模拟这个过程就可以
考虑第四、五个包怎么做,存在一个
由于开始会把所在的格子染红,所以起点在红与蓝上的情况会不同,简单分情况考虑一下:
- 若起点
i 为红色:- 若
n - t \ge i ,则t \gets t + i ; - 否则,
t \gets t - (n - i + 1) ;
- 若
- 若起点
i 为蓝色:- 若
n - t - 1 \ge i ,则t \gets t + i + 1 ; - 否则,
t \gets t - (n - i) ;
- 若
可以发现,上述操作实际上是在模
那么,我们要求的,实际上就是一个区间内这个函数的复合。对于
直接维护函数值显然是很差的,我们能不能直接维护分段函数?看起来似乎复杂度爆炸,但是注意到我们只有查询操作没有修改操作,于是我们的线段树只要能建出来就行,而查询操作也不需要真的把函数复合找出来,因为我们只要求单点的值,所以查询的时候不需要将线段树上的若干个区间合并起来,于是我们不需要太关心合并两个区间的复杂度,不过我们还是需要关心分段函数的总段数的。
而注意到复合一次这个分段函数相当于进行
一般情况呢?注意到,任意局面进行若干次操作后,一定会变成上述的局面,而由于每次操作都是前缀染红与后缀染蓝,我们只需要维护前缀红的数量
如果操作的点不在
但是找
那么只需要把两部分拼在一起就做完这道题了。复杂度两个
有一些细节需要仔细考虑,大部分细节来自于操作时需要先把当前点修改为红色。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 120005, LOG = 18;
int n, m, T;
char s[MAXN];
int a[MAXN];
int px[MAXN], qx[MAXN], pc, qc, pi[MAXN], qi[MAXN];
int h(int x) { return x == 0 ? 0 : __lg(x) + 1; }
int nxt[LOG][LOG][MAXN];
long long ps[LOG][LOG][MAXN], qs[LOG][LOG][MAXN];
int preb[MAXN];
struct SegmentTree {
vector<pair<int, int>> t[MAXN << 2];
#define lc (i << 1)
#define rc (i << 1 | 1)
void build(int i = 1, int l = 1, int r = m) {
if (l == r) {
int v = a[l];
if (v == n) t[i] = { { v - 1, v + 1 - n - 1 }, { n, v - n - 1 } };
else if (n - v - 1 < v - 1) t[i] = { { n - v - 1, v + 1 }, { v - 1, v + 1 - n - 1 }, { n, v - n - 1 } };
else t[i] = { { v - 1, v + 1 }, { n - v, v }, { n, v - n - 1 } };
return;
}
int mid = (l + r) >> 1;
build(lc, l, mid), build(rc, mid + 1, r);
int L = 0;
for (auto [R, v] : t[lc]) {
auto it1 = lower_bound(t[rc].begin(), t[rc].end(), make_pair(L + v, INT_MIN));
auto it2 = lower_bound(t[rc].begin(), t[rc].end(), make_pair(R + v, INT_MIN));
for (auto it = it1; ; it++) {
int rr = it == it2 ? R + v : it->first;
t[i].push_back({ rr - v, v + it->second });
if (it == it2) break;
}
L = R + 1;
}
}
void query(int a, int b, int &v, int i = 1, int l = 1, int r = m) {
if (a <= l && r <= b) {
auto p = lower_bound(t[i].begin(), t[i].end(), make_pair(v, INT_MIN));
v += p->second;
return;
}
int mid = (l + r) >> 1;
if (a <= mid) query(a, b, v, lc, l, mid);
if (b > mid) query(a, b, v, rc, mid + 1, r);
}
} st;
int main() {
scanf("%d%d%s", &n, &m, s + 1);
for (int i = 1; i <= m; i++) scanf("%d", &a[i]);
for (int i = 1; i <= n + 1; i++) if (s[i] != 'R') px[++pc] = i - 1, pi[i - 1] = pc;
for (int i = n; i >= 0; i--) if (s[i] != 'B') qx[++qc] = n - i, pi[n - i] = qc;
for (int i = 1; i <= n; i++) preb[i] = preb[i - 1] + (s[i] == 'B');
for (int x = 0; x < LOG; x++) {
for (int y = 0; y < LOG; y++) {
int X = x == 0 ? 0 : (1 << (x - 1));
int Y = y == 0 ? 0 : (1 << (y - 1));
nxt[x][y][m + 1] = m + 1;
for (int i = m; i >= 1; i--) nxt[x][y][i] = (X < a[i] && a[i] < n + 1 - Y) ? i : nxt[x][y][i + 1];
for (int i = 1; i <= m; i++) {
ps[x][y][i] = (a[i] <= X ? a[i] : 0) + ps[x][y][i - 1];
qs[x][y][i] = (a[i] > n - Y ? n - a[i] : 0) + qs[x][y][i - 1];
}
}
}
st.build();
scanf("%d", &T);
while (T--) {
int l, r; scanf("%d%d", &l, &r);
int p = 1, q = 1;
int i = l - 1;
int t = -1;
auto Get = [&](int x) {
if (x <= px[p]) return 'R';
if (x > n - qx[q]) return 'B';
return s[x];
};
while (1) {
int x = h(px[p]), y = h(qx[q]);
int j = min(nxt[x][y][i + 1], r + 1);
int dp = min(ps[x][y][j - 1] - ps[x][y][i], 1ll * n);
int dq = min(qs[x][y][j - 1] - qs[x][y][i], 1ll * n);
if (px[min(pc, p + dp)] + qx[min(qc, q + dq)] < n) {
p += dp, q += dq, i = j;
if (j == r + 1) break;
int bc = preb[n - qx[q]] - preb[px[p]] + qx[q], x = a[j] + (Get(a[j]) == 'B');
if (x <= bc) {
if (x >= bc - qx[q]) { t = n - qx[q] + (x - (bc - qx[q])), l = j + 1; break; }
else p += x;
} else {
int ac = n - bc, x = n - a[j] + (Get(a[j]) == 'R');
if (x >= ac - px[p]) { t = px[p] - (x - (ac - px[p])), l = j + 1; break; }
else q += x;
}
} else {
int L = i + 1, R = j - 1;
while (L < R) {
int mid = (L + R) >> 1;
int dp = min(ps[x][y][mid] - ps[x][y][i], 1ll * n);
int dq = min(qs[x][y][mid] - qs[x][y][i], 1ll * n);
if (px[min(pc, p + dp)] + qx[min(qc, q + dq)] < n) L = mid + 1;
else R = mid;
}
int dp = min(ps[x][y][L - 1] - ps[x][y][i], 1ll * n);
int dq = min(qs[x][y][L - 1] - qs[x][y][i], 1ll * n);
p += dp, q += dq, l = L + 1;
int bc = preb[n - qx[q]] - preb[px[p]] + qx[q], x = a[L] + (Get(a[L]) == 'B');
if (x <= bc) {
t = n - qx[q] + (x - (bc - qx[q]));
} else {
int ac = n - bc, x = n - a[L] + (Get(a[L]) == 'R');
t = px[p] - (x - (ac - px[p]));
}
break;
}
}
if (t == -1) {
int ans = px[p] + n - qx[q] - px[p] - (preb[n - qx[q]] - preb[px[p]]);
printf("%d\n", ans);
} else {
if (l <= r) st.query(l, r, t);
printf("%d\n", t);
}
}
return 0;
}