zoukankan      html  css  js  c++  java
  • BZOJ 1926: [Sdoi2010]粟粟的书架(主席树,二分答案)

    题意

    给你一个长为(R)宽为(C)的矩阵,第(i)(j)列的数为(P_{i,j}).

    (m)次询问,每次有5个参数(x_l,x_r,y_l,y_r,h). 求以((x_l,y_l))为左上角和((x_r,y_r))为右下角的矩形中,至少要选几个值,使得它们的和(geq h).

    数据范围

    对于(50 \%)的数据,满足(R,C le 200,M le 200,000)

    另有(50 \%)的数据,满足(R=1,C le 500,000,M le 20,000)

    对于(100 \%)的数据,满足(1 le P_{i,j} le 1,000, 1 le h le 2,000,000,000)

    题解

    这道题很有意思2333

    这个题相当于二合一吧,两种不同的方法解决它的子问题(但殊途同归).

    • 第一个(R,C le 200,M le 200,000).

      这个是有点类似于暴力的做法,首先预处理出每种数字出现次数的关于位置和数字大小前缀和,以及出现数字和关于位置数字大小的前缀和.

      这个有点绕,直接举例子吧.比如我程序中的Sum[i][j][k]Tot[i][j][k].

      Sum[i][j][k]就是以((1,1))为左上角((i,j))为右下角矩形的,数字(ge k)的和.

      Tot[i][j][k]就是以((1,1))为左上角((i,j))为右下角矩形的,数字(ge k)的出现次数的和.

      然后每次就可以二分你需要选的最小的数字了,每次判断可行就直接前缀和容斥就行了.

      然后这个选的最小数字不一定要选满,要最后算一下这个数字要选多少个.

      (n=max(P_{i,j}))时间复杂度(O(nRC+m log n)),空间复杂度(O(nRC)).

    • 第二个(R=1,C le 500,000,M le 20,000).

      这个就是一个序列操作了,这个我认为是这道题的精髓.

      我们沿用前一个算法的思想,也是要处理序列上那两个东西.

      但时间复杂度肯定要进行优化. 所以有一个数据结构可以支持这个操作,就是主席树!

      主席树不仅支持查找区间第(k)大,而且还能支持查找区间在([l,r])中数字的和 和 出现数字的和!(看来我数据结构学的真的蠢啊) 以后出现这种题要往这上面想想了.

      然后我们可以每次算答案的时候直接在主席树上二分就行了和刚才的操作差不多吧,也类似于查找第(k)大.

      时间复杂度(O(C log n + m log n)),空间复杂度(O(C log n)).

    代码 ​

    /**************************************************************
        Problem: 1926
        User: zjp_shadow
        Language: C++
        Result: Accepted
        Time:4688 ms
        Memory:509916 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    #define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
    #define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    using namespace std;
     
    bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
    bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
     
    inline int read() {
        int x = 0, fh = 1; char ch = getchar();
        for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
        for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
        return x * fh;
    }
     
    void File() {
    #ifdef zjp_shadow
        freopen ("P1926.in", "r", stdin);
        freopen ("P1926.out", "w", stdout);
    #endif
    }
     
    const int N = 5e5 + 1e3;
    const int maxnode = N * 20;
     
    int take;
     
    inline int Updiv(int a, int b) { return (a / b) + (a % b ? 1 : 0); }
     
    struct ChairMan_Tree {
        int T[N], sumv[maxnode], tot[maxnode], lc[maxnode], rc[maxnode], Size;
        ChairMan_Tree () { Size = 0; }
     
        void Update(int &o, int pre, int l, int r, int up) {
            o = ++Size; lc[o] = lc[pre]; rc[o] = rc[pre];
            sumv[o] = sumv[pre] + up; tot[o] = tot[pre] + 1;
            if (l == r) return ;
     
            int mid = (l + r) >> 1;
            if (up <= mid) Update(lc[o], lc[pre], l, mid, up);
            else Update(rc[o], rc[pre], mid + 1, r, up);
        }
     
        void Query(int s, int t, int l, int r, int val) {
            if (l == r) { take += Updiv(val, l); return ; }
            int here = tot[rc[t]] - tot[rc[s]], sv = sumv[rc[t]] - sumv[rc[s]], mid = (l + r) >> 1;
            if (val > sv) { take += here; Query(lc[s], lc[t], l, mid, val - sv); }
            else Query(rc[s], rc[t], mid + 1, r, val);
        }
    } CT;
     
    int r, c, m;
    int Mat[210][210];
    int Sum[210][210][1010];
    int Tot[210][210][1010];
     
    int sum[N];
     
    void Solve2() {
        For (i, 1, c) {
            int val = read();
            sum[i] = sum[i - 1] + val;
            CT.Update(CT.T[i], CT.T[i - 1], 1, 1000, val);
        }
        For (i, 1, m) {
            read(); int l = read(); read(); int r = read(), h = read();
        //  cout << "Ask: " << l << ' ' << r << ' ' << h << endl;
            take = 0;
            if (sum[r] - sum[l - 1] < h) { printf ("Poor QLW
    "); continue ; }
            CT.Query(CT.T[l - 1], CT.T[r], 1, 1000, h);
            printf ("%d
    ", take);
        }
    }
     
    inline int Calc_Sum (int xl, int yl, int xr, int yr, int low) {
        return Sum[xr][yr][low] - Sum[xl - 1][yr][low] - Sum[xr][yl - 1][low] + Sum[xl - 1][yl - 1][low];
    }
     
    inline int Calc_Tot (int xl, int yl, int xr, int yr, int low) {
        return Tot[xr][yr][low] - Tot[xl - 1][yr][low] - Tot[xr][yl - 1][low] + Tot[xl - 1][yl - 1][low];
    }
     
    void Solve1() {
        For (i, 1, r)
            For (j, 1, c) {
                Mat[i][j] = read(); Sum[i][j][Mat[i][j]] += Mat[i][j]; ++Tot[i][j][Mat[i][j]];
                For (k, 1, 1000) {
                    Sum[i][j][k] += Sum[i][j - 1][k] + Sum[i - 1][j][k] - Sum[i - 1][j - 1][k];
                    Tot[i][j][k] += Tot[i][j - 1][k] + Tot[i - 1][j][k] - Tot[i - 1][j - 1][k];
                }
            }
         
        For (i, 1, r)
            For (j, 1, c)
                Fordown (k, 1000, 1) {
                    Sum[i][j][k] += Sum[i][j][k + 1];
                    Tot[i][j][k] += Tot[i][j][k + 1];
                }
     
        For (i, 1, m) {
            int xi = read(), yi = read(), xj = read(), yj = read(), h = read();
            int l = 1, r = 1000, need = -1;
            while (l <= r) {
                int mid = (l + r) >> 1;
                if (Calc_Sum(xi, yi, xj, yj, mid) >= h) need = mid, l = mid + 1;
                else r = mid - 1;
            }
            if (need == -1) { printf ("Poor QLW
    "); continue ; }
            int Btot = Calc_Tot(xi, yi, xj, yj, need + 1),
                Bsum = Calc_Sum(xi, yi, xj, yj, need + 1);
            Btot += Updiv(h - Bsum, need);
            printf ("%d
    ", Btot);
        }
    }
     
    int main () {
        File();
        r = read(); c = read(); m = read();
        if (r == 1) Solve2(); else Solve1();
        return 0;
    }
    
  • 相关阅读:
    Hadoop概述
    Spring Security学习总结及源码分析
    Gradle在Mac上安装及Idea中配置
    MIT-6.S081-2020实验(xv6-riscv64)一:util
    数据库理论一些疑惑点
    com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
    vue Elemente-UI 管理后台自定义 导航菜单栏
    vue 处理跨域问题 (“No ‘Access-Control-Allow-Origin‘ header is present on the requested resource.”)
    修改伪元素content
    重写window.alert
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/8474037.html
Copyright © 2011-2022 走看看