描述
输入格式
第一行是三个正整数R, C, M。
接下来是一个 R行C 列的矩阵,从上到下、从左向右依次给出了每本书的 页数Pi,j。
接下来 M行,第 i 行给出正整数x1i, y1i, x2i, y2i, Hi,表示第i 天的指定区域 是﹙x1i, y1i﹚与﹙x2i, y2i﹚间的矩形,总页数之和要求不低于 Hi。
保证 1≤x1i≤x2i≤R,1≤y1i≤y2i≤C。
输出格式
有M行,第i 行回答粟粟在第 i 天时为摘到苹果至少需要 拿取多少本书。
如果即使取走所有书都无法摘到苹果,则在该行输出“Poor QLW” (不含引号)。
样例输入1
5 5 7
14 15 9 26 53
58 9 7 9 32
38 46 26 43 38
32 7 9 50 28
8 41 9 7 17
1 2 5 3 139
3 1 5 5 399
3 3 4 5 91
4 1 4 1 33
1 3 5 4 185
3 3 4 3 23
3 1 3 3 108
样例输出1
6
15
2
Poor QLW
9
1
3
样例输入2
1 10 7
14 15 9 26 53 58 9 7 9 32
1 2 1 9 170
1 2 1 9 171
1 5 1 7 115
1 1 1 10 228
1 4 1 4 4570457
1 1 1 1 11
1 7 1 8 16
样例输出2
6
7
3
10
Poor QLW
1
2
提示
对于 10%的数据,满足 R, C≤10;
对于 20%的数据,满足 R, C≤40;
对于 50%的数据,满足 R, C≤200,M≤200,000;
另有 50%的数据,满足 R=1,C≤500,000,M≤20,000;
对于 100%的数据,满足 1≤Pi,j≤1,000,1≤Hi≤2,000,000,000。
题解
观察数据范围,一半数据的矩阵只有一行,另一半R、C较小。考虑分类讨论。
当矩阵只有一行时,原题变为在一数列中多次询问,每次给定l、r、h,询问从区间[l , r]中选取一些数字,使总和大于或等于h的最小选取个数。考虑主席树。
第i 棵线段树中某一区间[l , r]维护数列前i 个数中,值在[l , r]内的数的个数与总和,用可持久化优化时间、空间。
对于提问[x , y],第y 棵线段树减去第x-1 棵线段树,就可以得到[x , y]中不同区间内的值的数出现的次数与这些数的总和。使用类似二分的方法讨论答案。
当R, C≤200时,考虑预处理优化。
count[i][j][k]记录前i 行j 列中,值大于或等于k 的数的个数,value[i][j][k]记录这些数的总和。
对于每个询问,二分k的值,得到答案。
但是注意,某个值的数不一定全用,因此还要处理答案。具体见代码。
代码
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const ll Q=6000000;
ll n,maxn=1000,m,ls[Q],rs[Q],cnt[Q],a[500005],sum[Q],tot,maxr=1000,q,co[201][201][1005],v[201][201][1005];
void mt(ll now,ll l,ll r)
{
if(l==r)return;
ls[now]=++tot;
rs[now]=++tot;
ll mid=(l+r)>>1;
mt(ls[now],l,mid);
mt(rs[now],mid+1,r);
}
void xiu(ll now,ll last,ll l,ll r,ll v)
{
cnt[now]=cnt[last]+1,sum[now]=sum[last]+v;
if(l==r)return;
ll mid=(l+r)>>1;
ls[now]=ls[last];
rs[now]=rs[last];
if(v<=mid)ls[now]=++tot,xiu(ls[now],ls[last],l,mid,v);
else rs[now]=++tot,xiu(rs[now],rs[last],mid+1,r,v);
}
ll gs(ll nowl,ll nowr,ll l,ll r,ll v)
{
if(sum[nowr]-sum[nowl]<v)return 999999999;
if(l==r)return (v-1)/l+1;
ll mid=(l+r)>>1,lrs=rs[nowl],rrs=rs[nowr];
if(sum[rrs]-sum[lrs]>=v)return gs(lrs,rrs,mid+1,r,v);
else return cnt[rrs]-cnt[lrs]+gs(ls[nowl],ls[nowr],l,mid,v-(sum[rrs]-sum[lrs]));
}
void MoD()
{
ll j,i,x,y,h;
n=tot=m;
mt(0,1,maxr);
for(i=1;i<=n;i++)
{
scanf("%lld",&x);
xiu(i,i-1,1,maxr,x);
}
while(q--)
{
scanf("%lld%lld%lld%lld %lld",&i,&x,&j,&y,&h);
i=gs(x-1,y,1,maxr,h);
i<999999999?printf("%lld\n",i):printf("Poor QLW\n");
}
}
int main()
{
ll k,i,j,x,h,y;
scanf("%lld%lld%lld",&n,&m,&q);
if(n==1){
MoD();
return 0;
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%lld",&x);
for(k=1;k<=x;k++)
co[i][j][k]++,v[i][j][k]+=x;
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
for(k=1;k<=1000;k++)
{
co[i][j][k]+=co[i-1][j][k]+co[i][j-1][k]-co[i-1][j-1][k];
v[i][j][k]+=v[i-1][j][k]+v[i][j-1][k]-v[i-1][j-1][k];
}
while(q--)
{
scanf("%lld%lld%lld%lld%lld",&i,&j,&x,&y,&h);
ll l=1,r=maxn,www,wdf;
while(l<=r)
{
ll mid=(l+r)>>1;
if(v[x][y][mid]-v[x][j-1][mid]-v[i-1][y][mid]+v[i-1][j-1][mid]>=h)l=mid+1;
else r=mid-1;
}
if(r==0){
printf("Poor QLW\n");
continue;
}
www=h-(v[x][y][r+1]-v[x][j-1][r+1]-v[i-1][y][r+1]+v[i-1][j-1][r+1]);
wdf=co[x][y][r+1]-co[x][j-1][r+1]-co[i-1][y][r+1]+co[i-1][j-1][r+1];
printf("%lld\n",wdf+(www-1)/r+1);
}
return 0;
}