「题解」洛谷 P3586 [POI2015]LOG
题目
简化题意
维护一个序列(一开始都是 \(0\))可以单点修改,支持询问能不进行 \(s\) 次每次挑 \(x\) 个正数,并减 \(1\)(并不是真正的减)的操作。
思路
考虑每个数在一次询问中的贡献
- 一个数如果大于 \(s\) 那么它能够被选 \(s\) 次。
- 一个数如果小于 \(s\) 那么它能够被选它的大小次。
所以只需要判断 \(\large\sum\limits_{i = 1}^{n} \min(s,a[i])\) 是否大于 \(s \times x\) 就行。
考虑去维护小于 \(s\) 的数目以及他们的和。
开两个树状数组,下标都是离散化过的,一个存离散化过后下标这么大的数出现过几次,一个存离散化过后下标这么大数在离散化之前的权值。
感觉维护有点麻烦所以在代码中详细写了下注释
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 1000001
#define int long long
int n, m, num0, a[MAXN], lsh1[MAXN], lsh2[MAXN];
//a 是离散化之前的序列.
//lsh2 是离散化之后的序列.
//lsh1 是对题目询问中权值离散化.
struct query {
int opt, x, y;
}q[MAXN];
struct lsh {
int w, id;
friend bool operator < (lsh l1, lsh l2) {
return l1.w < l2.w;
}
}c[MAXN];
struct BIT {
int c[MAXN];
int lowbit(int x) { return x & (-x); }
void add(int x, int k) {
while (x <= m) {
c[x] += k;
x += lowbit(x);
}
}
int sum(int x) {
int ans = 0;
while (x) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
}b[2];
//b[0] 离散化后个数
//b[1] 离散化前数量
signed main() {
scanf("%lld %lld", &n, &m), num0 = n;
char opt;
for (int i = 1; i <= m; ++i) {
while (opt != 'U' && opt != 'Z') opt = getchar();
scanf("%lld %lld", &q[i].x, &q[i].y);
q[i].opt = (opt == 'U' ? 1 : 0);
c[i].w = q[i].y, c[i].id = i;
opt = getchar();
}
std::sort(c + 1, c + m + 1);
for (int i = 1, now = 0; i <= m; ++i) {
if (c[i].w != c[i - 1].w) ++now;
lsh1[c[i].id] = now;
}//离散化
for (int i = 1; i <= m; ++i) {
if (q[i].opt) {
if (lsh2[q[i].x] != 0) b[0].add(lsh2[q[i].x], -1);
//如果离散化后的序列中这个元素不是 0 就给它的出现次数减 1.
else if (lsh2[q[i].x] == 0 && lsh1[i] != 0) --num0;
//更改序列中 0 的数目.
if (lsh1[i] != 0) b[0].add(lsh1[i], 1);
//如果离散化后的更改操作不是 0 就给它的出现次数加 1.
else if (lsh2[q[i].x] != 0) ++num0;
//更改序列中 0 的数目.
if (lsh2[q[i].x] != 0) b[1].add(lsh2[q[i].x], -a[q[i].x]);
//更改大小.
if (lsh1[i] != 0) b[1].add(lsh1[i], q[i].y);
//更改大小.
a[q[i].x] = q[i].y, lsh2[q[i].x] = lsh1[i];
//更改离散化前后原序列中的值.
}
else {
int bz1 = b[1].sum(lsh1[i]);//小于等于 s 的数的和
int bz2 = n - b[0].sum(lsh1[i]) - num0;//大于 s 的数的个数。
if (bz1 + bz2 * q[i].y >= q[i].x * q[i].y) puts("TAK");
else puts("NIE");
}
}
return 0;
}