专栏文章
莫队2+值域分块
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioii3gz
- 此快照首次捕获于
- 2025/12/02 19:45 3 个月前
- 此快照最后确认于
- 2025/12/02 19:45 3 个月前
P3834 【模板】可持久化线段树 2
因为 ,但 ,因此对 数组进行离散化。
将 copy 到 中,记录 ,代表离散化后下标 对应的是 ,且将 替换为其在 中去重后的下标 。
令 为离散化后的值 在当前区间的出现次数, 为第 个块中所有元素的次数。
遍历每个块,用 找到包含了第 小元素的块,再枚举这个块,用 找到这个元素即可。
CPP#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, num, len, ans[N], sum[N], cnt[N], a[N], b[N];
map<int, int> f;
struct query {
int l, r, k, id;
} q[N];
bool cmp(query a, query b) {
return (a.l / len == b.l / len ? a.r < b.r : a.l < b.l);
}
void add_sub(int x, int val) {
int bl = x / num;
cnt[x] += val;
sum[bl] += val;
}
int rk(int k) {
for (int i = 0; i <= num; i++) {
if (k <= sum[i]) {
for (int j = i * num; j <= (i + 1) * num; j++) {
if (k <= cnt[j]) {
return j;
} else {
k -= cnt[j];
}
}
} else {
k -= sum[i];
}
}
return k + 1;
}
signed main() {
cin.tie(0), cout.tie(0)->sync_with_stdio(false);
cin >> n >> m;
len = sqrt(n);
num = n / len + (n % len > 0);
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i];
}
sort (b + 1, b + 1 + n);
int length = unique(b + 1, b + 1 + n) - (b + 1);
for (int i = 1; i <= n; i++) {
int x = lower_bound(b + 1, b + 1 + length, a[i]) - b;
f[x] = a[i];
a[i] = x;
}
for (int i = 1; i <= m; i++) {
cin >> q[i].l >> q[i].r >> q[i].k;
q[i].id = i;
}
sort (q + 1, q + 1 + m, cmp);
int l = 1, r = 0;
for (int i = 1; i <= m; i++) {
while (l > q[i].l)
add_sub(a[--l], 1);
while (r < q[i].r)
add_sub(a[++r], 1);
while (l < q[i].l)
add_sub(a[l++], -1);
while (r > q[i].r)
add_sub(a[r--], -1);
ans[q[i].id] = f[rk(q[i].k)];
}
for (int i = 1; i <= m; i++)
cout << ans[i] << '\n';
return 0;
}
P4137 Rmq Problem / mex
和 跟上一题一样。
对于查询 mex,遍历所有块:
- 若 ,则块满了。
- 若 ,说明有一个没出现的数字,再根据 找。
注意判断所有块都满的情况,输出 。
CPP#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, num, len, ans[N], cnt[N], siz[N], L[N], R[N], pos[N], a[N], sum[N];
struct query {
int l, r, id;
} q[N];
bool cmp(query a, query b) {
if (a.l / len != b.l / len) {
return a.l < b.l;
}
if (a.l / len % 2)
return a.r > b.r;
return a.r < b.r;
}
void init() {
len = sqrt(2e5);
num = 2e5 / len + (2e5 / len > 0);
for (int i = 1; i <= num; i++) {
L[i] = (i - 1) * len + 1;
R[i] = i * len;
siz[i] = len;
}
R[num] = 2e5;
siz[num] = R[num] - L[num] + 1;
L[1] = 0;
siz[1]++;
for (int i = 1; i <= num; i++) {
for (int j = L[i]; j <= R[i]; j++) {
pos[j] = i;
}
}
}
void ADD(int x) {
cnt[a[x]]++;
(cnt[a[x]] == 1) && (sum[pos[a[x]]]++);
}
void SUB(int x) {
cnt[a[x]]--;
(cnt[a[x]] == 0) && (sum[pos[a[x]]]--);
}
int query() {
for (int i = 1; i <= num; i++) {
if (sum[i] == siz[i]) {
continue;
}
for (int j = L[i]; j <= R[i]; j++) {
if (cnt[j] == 0)
return j;
}
}
return R[num] + 1;
}
signed main() {
cin.tie(0), cout.tie(0)->sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
init();
for (int i = 1; i <= m; i++) {
cin >> q[i].l >> q[i].r;
q[i].id = i;
}
sort (q + 1, q + 1 + m, cmp);
int l = 1, r = 0;
for (int i = 1; i <= m; i++) {
while (l > q[i].l)
ADD(--l);
while (r < q[i].r)
ADD(++r);
while (l < q[i].l)
SUB(l++);
while (r > q[i].r)
SUB(r--);
ans[q[i].id] = query();
}
for (int i = 1; i <= m; i++)
cout << ans[i] << '\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...