zoukankan      html  css  js  c++  java
  • 「题解」洛谷 P3586 [POI2015]LOG

    题目

    P3586 [POI2015]LOG

    简化题意

    维护一个序列(一开始都是 (0))可以单点修改,支持询问能不进行 (s) 次每次挑 (x) 个正数,并减 (1)(并不是真正的减)的操作。

    思路

    考虑每个数在一次询问中的贡献

    • 一个数如果大于 (s) 那么它能够被选 (s) 次。
    • 一个数如果小于 (s) 那么它能够被选它的大小次。

    所以只需要判断 (largesumlimits_{i = 1}^{n} min(s,a[i])) 是否大于 (s imes 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;
    }
    
  • 相关阅读:
    Google基本利用
    sqlmap
    kali中wireshark打开后错误
    Python Flask Jinja2模板引擎
    Python Flask学习
    Python 豆瓣日记爬取
    Python 函数装饰器
    Python 生成器
    ss源码学习--从协议建立到完成一次代理请求
    ss源码学习--工作流程
  • 原文地址:https://www.cnblogs.com/poi-bolg-poi/p/13598188.html
Copyright © 2011-2022 走看看