先观察这个题的数据范围
显然这是一个二合一的题目。
当 R = 1 R=1 R=1的时候这道题可以用主席树来做,否则这个题就是一个二维前缀和+二分
先说 R > 1 R>1 R>1的情况:
维护一个二维前缀和,并且要记录大于等于某一值的二维前缀和(小于的取0),查询的时候二分这个值(值域是 [ 1 , 1000 ] [1,1000] [1,1000]),二分这个值域,求得某一值的前缀和,这个前缀和满足大于 H i H_i Hi,然后就可以记录最少需要的书本数。无解的时候需要特判。
再说 R = 1 R=1 R=1的情况,如果再用前缀和+二分的话,时间复杂度会过大,所以直接采取主席树维护区间和的方式即可,同时还要维护区间内部值出现的次数。查询的时候需要向上取整。无解的时候需要特判。
具体做法就是维护区间和,与这两个题很像
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <deque>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#include <bitset>
#include <set>
#include <map>
//#include <unordered_map>
#define inf 0x7fffffff
//#define ll long long
//#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
//const int mod=1000000007;
const int M=5e6;
const int maxn=4;
const int len=4;
const int N=5e5+5;//?????????? 4e8
int sum[205][205][1005],cnt[205][205][1005];
int n,m,q;
int a1,b1,a2,b2;
int p[205][205];
int getsum(int k)
{
return sum[a2][b2][k]-sum[a1-1][b2][k]-sum[a2][b1-1][k]+sum[a1-1][b1-1][k];
}
int getcnt(int k)
{
return cnt[a2][b2][k]-cnt[a1-1][b2][k]-cnt[a2][b1-1][k]+cnt[a1-1][b1-1][k];
}
void solve2()
{
int ma=0;
for(re i=1;i<=n;i++) for(re j=1;j<=m;j++) scanf("%d",&p[i][j]),ma=max(p[i][j],ma);
for(re k=0;k<=ma;k++) for(re i=1;i<=n;i++) for(re j=1;j<=m;j++)
{
sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(p[i][j]>=k?p[i][j]:(int)0);
cnt[i][j][k]=cnt[i-1][j][k]+cnt[i][j-1][k]-cnt[i-1][j-1][k]+(p[i][j]>=k);
}
while(q--)
{
int k;
scanf("%d%d%d%d%d",&a1,&b1,&a2,&b2,&k);
if(getsum(0)<k)
{
puts("Poor QLW");
continue;
}
int l=0,r=ma+1,ans=-1;
while(l+1<r)
{
int mid=(l+r)>>1;
if(getsum(mid)>=k) l=mid,ans=mid;
else r=mid;
}
if(ans==-1) puts("Poor QLW");
else printf("%d\n",getcnt(ans)-(getsum(ans)-k)/ans);
}
}
struct node
{
int l,r,sum,cnt;
}e[N*40];
int rt[N],tot,a[N];
void insert(int &p,int pre,int l,int r,int pos)
{
e[++tot]=e[pre];
p=tot;
e[p].cnt++;
e[p].sum+=pos;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) insert(e[p].l,e[pre].l,l,mid,pos);
else insert(e[p].r,e[pre].r,mid+1,r,pos);
}
int ask(int L,int R,int l,int r,int k)
{
if(l==r) return (k-1)/l+1;
int mid=(l+r)>>1;
int cnt=e[e[R].r].cnt-e[e[L].r].cnt;
int sum=e[e[R].r].sum-e[e[L].r].sum;
if(sum<k) return cnt+ask(e[L].l,e[R].l,l,mid,k-sum);
return ask(e[L].r,e[R].r,mid+1,r,k);
}
void solve1()
{
for(re i=1;i<=m;i++) scanf("%d",&a[i]);
for(re i=1;i<=m;i++) insert(rt[i],rt[i-1],1,1000,a[i]);
while(q--)
{
int k;
scanf("%d%d%d%d%d",&a1,&b1,&a2,&b2,&k);
if(e[rt[b2]].sum-e[rt[b1-1]].sum<k) puts("Poor QLW");
else printf("%d\n",ask(rt[b1-1],rt[b2],1,1000,k));
}
}
void solve()
{
cin>>n>>m>>q;
if(n==1) solve1();
else solve2();
}
signed main()
{
int T=1;
// cin>>T;
for(int index=1;index<=T;index++)
{
// printf("Case %lld:\n",index);
solve();
// puts("");
}
return 0;
}
/*
*/