• P2468 [SDOI2010]粟粟的书架 题解


    Description

    Luogu传送门

    Solution

    观察到数据范围:

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

    另有 \(50\%\) 的数据,满足 \(R = 1, C \leq 5 \times 10^5\)

    ……

    明显要进行数据分治了。。

    Subtask_1

    直接暴力计算二维前缀和,然后二分查询即可。

    具体来说,枚举一个 \(k (1 \leq k \leq 1000)\),然后把 \(\geq k\) 的数赋值为 1,\(< k\) 的数赋值为 0。

    预处理时间复杂度:\(O(1000nm)\)

    查询时间复杂度:\(O(q\log 1000)\)

    Subtask_2

    这时就变成了在一个一维数组上查询,那么就一个主席树板子。

    不多解释了,直接看代码吧。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    namespace IO{
        inline int read(){
            int x = 0;
            char ch = getchar();
            while(!isdigit(ch)) ch = getchar();
            while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
            return x;
        }
    
        template <typename T> inline void write(T x){
            if(x < 0) putchar('-'), x = -x;
            if(x > 9) write(x / 10);
            putchar(x % 10 + '0');
        }
    }
    using namespace IO;
    
    const int V = 1000;
    int n, m, q;
    
    namespace Subtask_1{
    
        int a[210][210], sum[210][210][V + 10], cnt[210][210][V + 10];
    
        inline void prework(){
            int mx = 0;
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= m; ++j)
                    a[i][j] = read(), mx = max(mx, a[i][j]);
            for(int k = 1; k <= mx; ++k)
                for(int i = 1; i <= n; ++i)
                    for(int j = 1; j <= m; ++j){
                        sum[i][j][k] = sum[i][j - 1][k] + sum[i - 1][j][k] - sum[i - 1][j - 1][k] + (a[i][j] >= k ? a[i][j] : 0);
                        cnt[i][j][k] = cnt[i][j - 1][k] + cnt[i - 1][j][k] - cnt[i - 1][j - 1][k] + (a[i][j] >= k);
                    }
        }
    
        inline int Sum(int x1, int y1, int x2, int y2, int k){
            return sum[x2][y2][k] - sum[x2][y1 - 1][k] - sum[x1 - 1][y2][k] + sum[x1 - 1][y1 - 1][k];
        }
    
        inline int Cnt(int x1, int y1, int x2, int y2, int k){
            return cnt[x2][y2][k] - cnt[x2][y1 - 1][k] - cnt[x1 - 1][y2][k] + cnt[x1 - 1][y1 - 1][k];
        }
    
        inline int solve(){
            prework();
            while(q--){
                int x1 = read(), y1 = read(), x2 = read(), y2 = read(), h = read();
                if(Sum(x1, y1, x2, y2, 1) < h){
                    puts("Poor QLW");
                    continue;
                }
                int l = 1, r = V, res = 0;
                while(l <= r){
                    int mid = (l + r) >> 1;
                    if(Sum(x1, y1, x2, y2, mid) >= h) res = mid, l = mid + 1;
                    else r = mid - 1;
                }
                write(Cnt(x1, y1, x2, y2, res) - (Sum(x1, y1, x2, y2, res) - h) / res), puts("");
            }
            return 0;
        }
    }
    
    namespace Subtask_2{
        #define ls(x) t[x].l
        #define rs(x) t[x].r    
        const int N = 5e5 + 10;
    
        struct Tree{
            int sum, cnt, l, r;
        }t[N << 6];
        int root[N << 6], cnt, H;
        int a[N], b[N];
    
        inline int update(int pre, int l, int r, int x){
            int rt = ++cnt;
            ls(rt) = ls(pre), rs(rt) = rs(pre), t[rt].sum = t[pre].sum + x, t[rt].cnt = t[pre].cnt + 1;
            if(l == r) return rt;
            int mid = (l + r) >> 1;
            if(x <= mid) ls(rt) = update(ls(pre), l, mid, x);
            else rs(rt) = update(rs(pre), mid + 1, r, x);
            return rt;
        }
    
        inline int query(int L, int R, int h, int l, int r){
            if(l == r) return (h - 1) / l + 1;// ceil(h / l) 还需要的高度为 h,那么需要 ceil(h / l) 本书
            int Sum = t[rs(R)].sum - t[rs(L)].sum, Cnt = t[rs(R)].cnt - t[rs(L)].cnt;
            int mid = (l + r) >> 1;
            if(h <= Sum) return query(rs(L), rs(R), h, mid + 1, r);
            else return H -= Sum, Cnt + query(ls(L), ls(R), h - Sum, l, mid);
        }
    
        inline int solve(){
            for(int i = 1; i <= m; ++i){
                int x = read();
                root[i] = update(root[i - 1], 1, V, x);
            }
            while(q--){
                int x1 = read(), y1 = read(), x2 = read(), y2 = read(), h = read(), H = h;
                if(t[root[y2]].sum - t[root[y1 - 1]].sum < h) puts("Poor QLW");
                else write(query(root[y1 - 1], root[y2], h, 1, V)), puts("");
            }
            return 0;
        }
    }
    
    int main(){
        n = read(), m = read(), q = read();
        if(n > 1) Subtask_1 :: solve();
        else Subtask_2 :: solve();
        return 0;
    }
    

    \[\_EOF\_ \]

  • 相关阅读:
    又学到的2个小技巧
    CSS3 简写animation
    CSS3 区别Transform,Transition,Animation一句话
    纠错【2012年5月9日 JQuery跑马灯(文字无缝向上翻动)(自已封装的第三个插件)】
    jQuery计算选中的文本字数,并弹出一个层(插件四)
    html5Canvas绘制线条closePath();
    html5循环方式绘制矩形
    jQuery过滤not()与filter();
    javascript在firebug调试时用console.log
    jQuery插件在光标定位的地方插入文字(插件5)
  • 原文地址:https://www.cnblogs.com/xixike/p/15744782.html
Copyright © 2020-2023  润新知