专栏文章
题解:P14085 [ICPC 2023 Seoul R] Apricot Seeds
P14085题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minrorzc
- 此快照首次捕获于
- 2025/12/02 07:15 3 个月前
- 此快照最后确认于
- 2025/12/02 07:15 3 个月前
结论:长度为 的序列经过 轮冒泡后,下标区间 内的 个数,就是原序列中 内前 小的数。
证明:一方面,一个数在一轮冒泡过后,位置至多只会往左移动 ,所以在 轮冒泡后 内的数一定来自原序列的 这个区间。另一方面,如果把整个序列在 处截断,那么 轮冒泡后,最大的 个数一定会被移动到最后面的 个位置。于是证毕。
把询问看作两个前缀的答案相减,然后套用上面的结论,主席树维护即可。
代码
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1000005;
int n, m, k, len;
int a[maxn], rt[maxn];
int ind[maxn];
struct SegTree {
#define mid (l + r >> 1)
int ls[maxn << 5], rs[maxn << 5], c[maxn << 5], s[maxn << 5], cnt;
int update(int k, int l, int r, int qx) {
int dir = ++cnt; ls[dir] = ls[k], rs[dir] = rs[k]; c[dir] = c[k] + 1, s[dir] = s[k] + ind[qx];
if (l == r) return dir;
if (qx <= mid) ls[dir] = update(ls[k], l, mid, qx);
else rs[dir] = update(rs[k], mid + 1, r, qx);
return dir;
}
int query(int p, int q, int l, int r, int v) {
if (l == r) return v * ind[l];
int w = c[ls[q]] - c[ls[p]];
if (v <= w) return query(ls[p], ls[q], l, mid, v);
else return query(rs[p], rs[q], mid + 1, r, v - w) + s[ls[q]] - s[ls[p]];
}
} T;
void discrete() {
for (int i = 1; i <= n; i++) ind[i] = a[i];
sort(ind + 1, ind + 1 + n);
len = unique(ind + 1, ind + 1 + n) - ind - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(ind + 1, ind + 1 + len, a[i]) - ind;
}
int kth(int l, int r, int k) {return T.query(rt[l - 1], rt[r], 1, len, k);}
int query(int l, int r, int k, int x) {return kth(l, min(r, l + x + k - 1), x);}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
discrete();
for (int i = 1; i <= n; i++) rt[i] = T.update(rt[i - 1], 1, len, a[i]);
for (int i = 1; i <= m; i++) {
int l, r, k, x, y; cin >> l >> r >> k >> x >> y;
cout << query(l, r, k, y) - query(l, r, k, x - 1) << '\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...