栗栗的书架

本以为是线段树套主席书
不过看数据做题,大数据只有一条线。。
二分一个厚度直接大数据主席书
小数据暴力dp

// luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#define mid (l+r>>1)

using namespace std;
const int M=1000010;
int n,m,root[M],tot=0,a[2][M],q,b[201][201],maxn,sum[201][201][1010],num[201][201][1001];
struct OL_SEG{
    int l,r,num,sum;OL_SEG(){l=r=num=sum=0;}
}T[M];
void update(int o){T[o].sum=T[T[o].l].sum+T[T[o].r].sum;}
void modify(int &o,int pre,int l,int r,int ins){
    o=++tot;T[o]=T[pre];T[o].num++;
    if(l==r) {T[o].sum=T[o].num*l;return ;}
    if(ins<=mid)modify(T[o].l,T[pre].l,l,mid,ins);
    else modify(T[o].r,T[pre].r,mid+1,r,ins);
    update(o);
}
int query(int pre,int now,int l,int r,int ql,int qr) {
    if(l>qr||r<ql) return 0;
    if(ql<=l&&r<=qr) return T[now].sum-T[pre].sum;
    return query(T[pre].l,T[now].l,l,mid,ql,qr)+query(T[pre].r,T[now].r,mid+1,r,ql,qr);
}
int query2(int pre,int now,int l,int r,int ql,int qr) {
    if(l>qr||r<ql) return 0;
    if(ql<=l&&r<=qr) return T[now].num-T[pre].num;
    return query2(T[pre].l,T[now].l,l,mid,ql,qr)+query2(T[pre].r,T[now].r,mid+1,r,ql,qr);
}
int ask(int x,int y,int xx,int yy,int w){return sum[xx][yy][w]-sum[x][yy][w]-sum[xx][y][w]+sum[x][y][w];}
int ask2(int x,int y,int xx,int yy,int w){return num[xx][yy][w]-num[x][yy][w]-num[xx][y][w]+num[x][y][w];}
int main(){
    scanf("%d%d%d",&n,&m,&q);

    if(n==1){for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]),modify(root[j],root[j-1],0,1000,a[i][j]);
        while(q--){int x,y,xx,yy,h;
        scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&h);
        int l=0,r=10000000;
        while(l<=r){
            if(query(root[y-1],root[yy],0,1000,mid,1000)>=h) l=mid+1;
            else r=mid-1;
        }
        if(!l) {printf("Poor QLW\n");continue;}
        int w1=query(root[y-1],root[yy],0,1000,l-1,1000),w2=query2(root[y-1],root[yy],0,1000,l-1,1000);
        while(w1-l+1>=h)w1-=l-1,w2--;
        printf("%d\n",w2);
        }
    }else{
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&b[i][j]),maxn=max(maxn,b[i][j]);
        for(int i=0;i<=maxn;i++)for(int j=1;j<=n;j++)for(int k=1;k<=m;k++)
        sum[j][k][i]=sum[j][k-1][i]+sum[j-1][k][i]-sum[j-1][k-1][i]+((b[j][k]>=i)?b[j][k]:0),
        num[j][k][i]=num[j][k-1][i]+num[j-1][k][i]-num[j-1][k-1][i]+((b[j][k]>=i)?1:0);
        while(q--){int x,y,xx,yy,h;
        scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&h);
        int l=0,r=maxn+1;
        while(l<=r){
            if(ask(x-1,y-1,xx,yy,mid)>=h) l=mid+1;
            else r=mid-1;
        }
        if(!l) {printf("Poor QLW\n");continue;}
        int w1=ask(x-1,y-1,xx,yy,l-1),w2=ask2(x-1,y-1,xx,yy,l-1);
        while(w1-l+1>=h)w1-=l-1,w2--;
        printf("%d\n",w2);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值