题意:
给定一个序列,定义一次操作选择序列中一个元素, 使,其中为当前序列中的最大偶数,若没有则是最大奇数。
有组询问,每次给定分别表示操作次数和操作区间,每次回答操作完成后区间中的,询问间互相独立。
Solution:
不管奇数还是偶数,操作次数始终是次,所以一共能操作次
考虑一次询问的,区间为次的情况,如果那么每次一操作的元素下标是一定的,令该序列为
考虑获取这个序列,优先队列模拟即可
考虑任意选择区间,,容易知道此时的操作序列一定为的一个子序列,令该序列为, 那随着缩小,新的操作序列一定为的一个前缀
考虑以建立棵线段树,每棵线段树内部维护信息为,内部下标为,那么第棵线段树中记录执行到第次操作时对区间的操作次数,那么就是维护一个区间最大值,每次操作都是单点修改,只会改变一条链,故建立可持久化线段树。
考虑解决询问,我们只要每次二分这个版本,找到第一个区间内操作次数的版本即可,然后输出区间最大值即为答案
时间复杂度,空间复杂度
比题解低能,但是思想简单,写法简单,但是没写出来🤡
Code:
int n, q;
int a[maxn];
struct node {
int x, id;
bool operator<(const node &t) const {
if (t.x % 2 != x % 2) return x % 2 > t.x % 2;
if (x != t.x) return x < t.x;
return id > t.id;
}
};
priority_queue<node> Q;
void solve(int cas) {
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
if (a[i]) Q.push((node){a[i], i});
}
build(root[0], 1, n);
int cnt = 0;
while (!Q.empty()) {
node p = Q.top(); Q.pop();
auto [x, id] = p;
update(root[cnt], root[cnt + 1], 1, n, id, 1);
cnt++;
if (x / 2 > 0) Q.push({x >>= 1, id});
}
for (int i = 1; i <= q; ++i) {
int l, r, k; cin >> l >> r >> k;
int L = 1, R = cnt, t = 0;
while (L <= R) {
int mid = L + R >> 1;
if (query(root[mid], 1, n, l, r) <= k) {
t = mid;
L = mid + 1;
} else R = mid - 1;
}
cout << query_Max(root[t], 1, n, l, r) << '\n';
}
}