Luogu 3586 [POI2015]LOG
考虑离散化后开权值线段树。
设序列中不小于$s$的数有$cnt$个,小于$s$的数的和为$sum$。
那么操作Z能成功的充要条件是$sum \geq (c - cnt) * s$。
如果序列中不小于$s$的数超过了$c$个,那么直接每一次都选这些数就好了。
如果没有超过$c$个的话,这$cnt$个数每一次都要选,然后再贪心地取剩下的数中最大的就行了。
需要把询问中出现的$a, s$和$0$一起离散化。
细节没想清楚WA好久
膜Claris
Code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 1e6 + 5; const int inf = 1 << 30; int n, qn, tot = 0, maxn = 0, a[N]; ll b[N << 1]; struct Querys { int type, x, y; } q[N]; struct Innum { int val, id; } in[N << 1]; bool cmp(const Innum &x, const Innum &y) { if(x.val != y.val) return x.val < y.val; else return x.id < y.id; } inline int max(int x, int y) { return x > y ? x : y; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void discrete() { in[0].val = -inf; sort(in + 1, in + 1 + tot, cmp); for(int cnt = 0, i = 1; i <= tot; i++) { if(in[i].val != in[i - 1].val) cnt++; maxn = max(maxn, cnt); b[cnt] = in[i].val; q[in[i].id].y = cnt; } } namespace SegT { ll s[N << 3]; int cnt[N << 3]; #define lc p << 1 #define rc p << 1 | 1 #define mid ((l + r) >> 1) inline void up(int p) { if(p) { s[p] = s[lc] + s[rc]; cnt[p] = cnt[lc] + cnt[rc]; } } void modify(int p, int l, int r, int x, int v) { if(x == l && r == x) { s[p] += (ll)b[l] * v; cnt[p] += v; return; } if(x <= mid) modify(lc, l, mid, x, v); else modify(rc, mid + 1, r, x, v); up(p); } ll qSum(int p, int l, int r, int x, int y) { if(x > y) return 0LL; if(x <= l && y >= r) return s[p]; ll res = 0LL; if(x <= mid) res += qSum(lc, l, mid, x, y); if(y > mid) res += qSum(rc, mid + 1, r, x, y); return res; } int qCnt(int p, int l, int r, int x, int y) { // if(x > y) return 0; if(x <= l && y >= r) return cnt[p]; int res = 0; if(x <= mid) res += qCnt(lc, l, mid, x, y); if(y > mid) res += qCnt(rc, mid + 1, r, x, y); return res; } } using namespace SegT; int main() { read(n), read(qn); in[++tot] = (Innum) {0, 0}; for(int i = 1; i <= qn; i++) { char op[3]; scanf("%s", op); read(q[i].x), read(q[i].y); if(op[0] == 'U') q[i].type = 1, in[++tot] = (Innum) {q[i].y, i}; else q[i].type = 2, in[++tot] = (Innum) {q[i].y, i}; } discrete(); /* for(int i = 1; i <= maxn; i++) printf("%lld ", b[i]); printf("\n"); for(int i = 1; i <= qn; i++) printf("%d %d %d\n", q[i].type, q[i].x, q[i].y); printf("\n"); */ for(int i = 1; i <= n; i++) a[i] = 1, modify(1, 1, maxn, 1, 1); for(int i = 1; i <= qn; i++) { if(q[i].type == 1) { modify(1, 1, maxn, a[q[i].x], -1); modify(1, 1, maxn, q[i].y, 1); a[q[i].x] = q[i].y; } else { int cnt = qCnt(1, 1, maxn, q[i].y, maxn); /* if(cnt >= q[i].x) { puts("TAK"); continue; } */ ll sum = qSum(1, 1, maxn, 1, q[i].y - 1); if(sum >= (q[i].x - cnt) * b[q[i].y]) puts("TAK"); else puts("NIE"); } } return 0; }