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\_ \]

posted @ 2021-12-29 14:18  xixike  阅读(30)  评论(0编辑  收藏  举报