目录
- 学术
E - A += v
- @ 2026-3-15 21:58:34
【二分、树状数组】E - A += v
给定一个长度为 的序列 ,元素取值在 之间。执行 次操作:每次选取 中出现次数最少且数值最小的元素 ,将其追加到 的末尾。给出 次独立查询,每次询问操作完成后第 个位置的元素取值。数据范围:$N, M \le 5 \times 10^5, Q \le 2 \times 10^5, X_i \le 10^{18}$。
本题的核心在于洞察频率变化过程的周期性与单调性。初始状态下,序列长度为 。设 为元素 在初始序列中的出现次数,并记 。
考虑操作的确定性机制:每次必然选取当前出现次数最小的元素,且数值较小者优先。这意味着元素的追加顺序严格遵循以 为第一、第二关键字的字典序升序排列。由此可以建立分层模型:将元素的频率增加过程分为若干层。在第 层中(),所有满足初始频率 的元素 将被依次追加一次,使得它们的频率提升至 。当经历 层后,所有 个元素的频率均达到 ,此后整个序列将退化为严格的周期循环,即反复追加序列 。
基于上述分层模型,我们可以将查询按位置 划分为两类:
- 若目标位置落在前 层内(即前缀非周期部分),可通过预处理各层的元素总数,计算其前缀和 。对于给定的相对偏移量 ,利用二分查找快速定位其所属的层级 及在该层中的相对位次 。此时问题转化为:求所有满足 的元素中,数值第 小的元素。将所有此类查询按层级 离线分组,并利用树状数组动态维护当前激活的元素集合,辅以树状数组上的倍增算法(Binary Lifting),即可在 的时间内高效响应查询。
- 若目标位置落在 层之后(即严格周期部分),由于周期长度固定为 ,且元素序列严格为 到 ,直接利用同余运算取模即可得出答案。
综上,通过离线查询与动态维护结合,将复杂的无穷次操作转化为有限层内的二维偏序查询。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int n, m;
int a[500005];
int c[500005];
ll w[500005];
ll p[500005];
ll ans[200005];
int bit[500005];
struct Req {
int pos;
int id;
};
vector<int> gp[500005];
vector<Req> qu[500005];
void upd(int x, int v) {
for (; x <= m; x += x & -x) bit[x] += v;
}
int kth(int r) {
int id = 0;
for (int i = 19; i >= 0; i--) {
int nx = id + (1 << i);
if (nx <= m && bit[nx] < r) {
id = nx;
r -= bit[id];
}
}
return id + 1;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int q;
cin >> n >> m;
int mx = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
c[a[i]]++;
}
for (int i = 1; i <= m; i++) {
mx = max(mx, c[i]);
gp[c[i]].push_back(i);
}
ll cur = 0;
for (int i = 0; i <= n; i++) {
cur += gp[i].size();
w[i] = cur;
if (i == 0) p[i] = w[i];
else p[i] = p[i - 1] + w[i];
}
cin >> q;
for (int i = 1; i <= q; i++) {
ll x;
cin >> x;
if (x <= n) {
ans[i] = a[x];
} else {
ll k = x - n;
if (k > p[mx - 1]) {
ll rem = (k - p[mx - 1] - 1) % m + 1;
ans[i] = rem;
} else {
int l = 0, r = mx - 1;
int res = 0;
while (l <= r) {
int mid = l + (r - l) / 2;
if (p[mid] >= k) {
res = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
int pos = k;
if (res > 0) pos -= p[res - 1];
qu[res].push_back({pos, i});
}
}
}
for (int i = 0; i < mx; i++) {
for (int x : gp[i]) upd(x, 1);
for (Req qy : qu[i]) ans[qy.id] = kth(qy.pos);
}
for (int i = 1; i <= q; i++) cout << ans[i] << "\n";
return 0;
}
时间复杂度:预处理层级与频率信息耗时 ,树状数组的单点更新与倍增查询分别为 ,共有 次离线查询与 次元素激活更新,总时间复杂度为 。
空间复杂度:主要由各数组与离线查询记录开销构成,为 。
0 条评论
目前还没有评论...
京公网安备11010802045784号
YIZHIYANG 一只羊 LV 8