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("
");
    for(int i = 1; i <= qn; i++)
        printf("%d %d %d
", q[i].type, q[i].x, q[i].y);
    printf("
");   */
    
    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;
}
View Code
原文地址:https://www.cnblogs.com/CzxingcHen/p/9524063.html