Solution
直接分块就可以了,对于每一块维护一个大根堆
每次操作对于整块的部分就直接先把待替换元素压进去,然后取出堆顶的元素
对于边界块就直接利用一个小根堆去暴力重构,然后直接依次从堆中取出最小的元素去替换就可以了,然后直接重建这个块的大根堆
时间复杂度(mathcal{O}(q cdot sqrt n cdot log(q + sqrt n)))
Code
#include <bits/stdc++.h>
using namespace std;
#define fst first
#define snd second
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef pair<int, int> pii;
inline int read() {
int sum = 0, fg = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
return fg * sum;
}
const int maxn = 4e5 + 10;
const int B = 577;
priority_queue<int> pq[maxn / B + 5];
int n, m, blks, a[maxn], S[maxn / B + 5][maxn], top[maxn / B + 5];
int pos(int x) { return (x - 1) / B + 1; }
void Set(int x) {
if (x <= 0 || x > blks) return;
priority_queue<int, vector<int>, greater<int> > now(S[x] + 1, S[x] + top[x] + 1);
int l = (x - 1) * B + 1, r = min(x * B, n);
for (int i = l; i <= r; i++) {
now.push(a[i]);
a[i] = now.top();
now.pop();
}
top[x] = 0;
}
int solve(int l, int r, int v) {
int x = pos(l), y = pos(r);
if ((l - 1) % B == 0) --x;
if (r % B == 0) ++y;
if (x == y) {
Set(x);
for (int i = l; i <= r; i++) if (a[i] > v) swap(a[i], v);
pq[x] = priority_queue<int>(a + (x - 1) * B + 1, a + x * B + 1);
} else {
Set(x), Set(y); int _l = x * B;
for (int i = l; i <= _l; i++) if (a[i] > v) swap(a[i], v);
pq[x] = priority_queue<int>(a + (x - 1) * B + 1, a + _l + 1);
++x, --y;
for (int i = x; i <= y; i++) {
if (pq[i].top() > v) {
pq[i].push(v);
S[i][++top[i]] = v;
v = pq[i].top();
pq[i].pop();
}
}
for (int i = y * B + 1; i <= r; i++) if (a[i] > v) swap(a[i], v);
pq[y + 1] = priority_queue<int>(a + y * B + 1, a + (y + 1) * B + 1);
}
return v;
}
int main() {
freopen("in.in", "r", stdin);
freopen("in.out", "w", stdout);
n = read(), m = read();
blks = (n - 1) / B + 1;
int cnt = 0;
for (int i = 1; i < blks; i++)
for (int j = 1; j <= B; j++)
pq[i].push(a[++cnt] = read());
for (int i = (blks - 1) * B + 1; i <= n; i++)
pq[blks].push(a[++cnt] = read());
while (m--) {
int l = read(), r = read(), v = read();
if (l <= r) printf("%d
", solve(l, r, v));
else printf("%d
", solve(1, r, solve(l, n, v)));
}
return 0;
}
Summary
其实我在考试的时候已经无限接近正解了,但是在想怎么重构块的时候卡住了。我一开始以为最终序列和操作的顺序有关,所以没想到直接把所有的操作元素放到一个小根堆里就可以了