bzoj1926: [Sdoi2010]粟粟的书架

题目链接

bzoj1926: [Sdoi2010]粟粟的书架

题解

看数据范围,发现这是两道题......0.5倍经验
对于R,C <= 200
前缀和+二分
前缀num[i][j][k]维护矩形(1,1)(i,j)中比k大的数有几个
sum[i][j][k] 维护维护矩形(1,1)(i,j)中比k大的数和为多少
在矩形中二分到k+1最后暴力填k
对于第二问变成了序列
二分取几个数(k)+主席树,用主席树维护权值,在主席树中取最大的k个数查看时否满足

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

using std::max;
int R,C,m;
inline int read () {
    int x = 0,f = 1;
    char c = getchar ();
    while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
    return x*f;
}
namespace Solve_1 {
#define maxn 207
    int a[maxn][maxn];
    int num[maxn][maxn][1007],sum[maxn][maxn][1007];
    int Max = 0;
    int  get_sum(int a,int b,int c,int d,int v) {
        return sum[c][d][v] - sum[a][d][v] - sum[c][b][v] + sum[a][b][v];
    }
    int  get_num(int a,int b,int c,int d,int v) {
        return num[c][d][v] - num[a][d][v] - num[c][b][v] + num[a][b][v];
    }
    int Get_Ans(int a,int b,int c,int d,int k,int need) {
        int ret = get_num(a,b,c,d,k+1);
        need -= get_sum(a,b,c,d,k+1);
        if(need>=0) {
            int num = need / k;
            ret += num; 
            need -= num * k;if(need > 0)ret++,need -= k;
        }
        return ret;
    }
    bool judge (int a,int b,int c,int d,int mid,int h) {
        //printf("%d\n",get_sum(a,b,c,d,mid));
        return get_sum(a,b,c,d,mid) > h ? true : false;
    }
    void work_Main() {
        memset(sum,0,sizeof sum);
        memset(num,0,sizeof num);
        for(int i = 1;i <= R;++ i) 
            for(int j = 1;j <= C;++ j) 
                a[i][j] = read(),Max = max (Max,a[i][j]);
        /*for(int i = 1;i <= R;++i) 
            for(int j = 1;j <= C;++ j) 
                for(int k = 1;k <= Max;++k) 
                    sum[i][j][k]= num[i][j][k] = 0;*/
        for(int k = 0;k <= Max;++ k) 
            for(int i = 1;i <= R;++ i) 
                for(int j = 1;j <= C;++ j) {
                    //printf("%d\n",sum[i][j][k]);
                    num[i][j][k] = num[i-1][j][k] + num[i][j-1][k] - num[i-1][j-1][k] + (a[i][j] >= k ?  1: 0);
                    sum[i][j][k] = sum[i-1][j][k] + sum[i][j-1][k] - sum[i-1][j-1][k] + (a[i][j] >= k ? a[i][j] : 0);
                }
        for(int a,b,c,d,h;m --;) {
            a = read() -1 ,b = read() -1,c = read(),d = read(),h = read(); 
            if(get_sum(a,b,c,d,0) < h) {
                puts("Poor QLW");continue;
            }
            int l = 1,r = Max,ans = 0; 
            while(l <= r) {
                int mid = l + r >> 1;
                if(judge(a,b,c,d,mid,h)) l = mid + 1,ans = mid;
                else r = mid - 1;
            }
            if(!ans) ans = 1;
            if(ans) printf("%d\n",Get_Ans(a,b,c,d,ans,h));
        }
    }
#undef maxn
}	
namespace Solve_2{
#define maxn 500007
#define lc t[x].ch[0]
#define rc t[x].ch[1]
    int a[maxn],tot = 0;
    int root[maxn];
    struct ChairMan_Tree {
        int ch[2],sum,sz;
        ChairMan_Tree() {
            sum=sz=ch[1]=ch[0]=0;
        }
    };
    ChairMan_Tree t[maxn << 4];
    int Max = 0;
    void update(int x) {
        t[x].sum = t[lc].sum + t[rc].sum;
    }
    void Insert(int pre,int &x,int l,int r,int p) {
        t[x = ++ tot].sz = t[pre].sz + 1,t[x].sum = t[pre].sum;
        if(l == r) {
            t[x].sum += p; return ;
        }
        int mid = l + r >> 1;
        if( p<=mid ) rc = t[pre].ch[1],Insert(t[pre].ch[0],lc,l,mid,p);
        else lc = t[pre].ch[0],Insert(t[pre].ch[1],rc,mid + 1,r,p);
        update(x);
    }
    int query(int pre,int x,int l,int r,int k) {
        if(t[x].sz <= t[pre].sz + k) return t[x].sum - t[pre].sum;
        if(l == r) return (t[x].sum - t[pre].sum) / (t[x].sz - t[pre].sz) *k;
        int mid = l + r >> 1;
        if(t[rc].sz >= t[t[pre].ch[1]].sz + k) return query(t[pre].ch[1],rc,mid + 1,r,k);
        else return query(t[pre].ch[0],lc,l,mid,k - t[rc].sz + t[t[pre].ch[1]].sz) + t[rc].sum - t[t[pre].ch[1]].sum;
    }
    void Work_Main() {
        Max = 1000;
        for(int i = 1;i<= C;++ i) 
            a[i] = read();//,Max = max(a[i],Max);
        for(int i = 1;i <= C;++ i) Insert(root[i-1],root[i],1,Max,a[i]);			
        for(int l,r,a,b,c,d,h;m --;) {
            a = read(),b = read() -1,c = read(),d = read(),h = read();
            l = 1,r = d - b + 1;
            while(l < r) {
                int mid = l + r >> 1; 
                if(query(root[b],root[d],1,Max,mid) >= h) r = mid;
                else l = mid + 1;
            }
            if(r == d - b + 1) puts("Poor QLW");
            else printf("%d\n",l);
        }
    }
}
int main() {
    R=read(),C=read(),m=read(); 
    if(R!=1) Solve_1::work_Main(); 
    else Solve_2::Work_Main();
}
    

posted @ 2018-04-03 14:58  zzzzx  阅读(200)  评论(0编辑  收藏  举报