题意:
给你一个
n
∗
m
n*m
n∗m的矩阵,每次询问一个矩形,左上角是
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1),右上角是
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2),和一个
h
h
h,问是否能选出矩阵中的若干个数使其和
≥
h
\ge h
≥h,能的话求出选的个数最少是多少个。
数据范围:
题意:
初看这题,没看范围,还以为是什么高级的数据结构,比如二维主席树什么的,听说二维主席树随便就能卡成
n
n
n\sqrt n
nn的,所以一直卡着没什么想法。最后看到了数据范围,直呼上当了。
可以将这个题分成两个题来做。
先看第二种
n
=
1
,
m
≤
5
e
5
n=1,m \le 5e5
n=1,m≤5e5。
这个显然就变成一个序列,我们只需要在序列上建立主席树,让后查询即可,变成了主席树裸题。
看第一种
n
,
m
≤
200
n,m\le200
n,m≤200。
有一种贪心的策略,那就是尽可能选
p
(
i
,
j
)
p(i,j)
p(i,j)大的数加上,这样选出来的一定个数最少,所以我们二分选的最小的
p
(
i
,
j
)
p(i,j)
p(i,j),让后现在我们需要快速求出来矩阵中
≥
p
(
i
,
j
)
\ge p(i,j)
≥p(i,j)的数的和,以及数量,这两个显然可以预处理出来,具体细节可以看代码。
注意求数量的时候,由于可能有多个都是
p
(
i
,
j
)
p(i,j)
p(i,j),所以要减去多余的。
// Problem: P2468 [SDOI2010]粟粟的书架
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2468
// Memory Limit: 500 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,M=2000,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m,q;
int a[201][201],g[201][201][1001],f[201][201][1001];
int root[N],tot;
struct Node {
int l,r;
int cnt;
int sum;
}tr[N*40];
void insert(int p,int &q,int l,int r,int pos) {
q=++tot; tr[q]=tr[p];
tr[q].cnt++; tr[q].sum+=pos;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) insert(tr[p].l,tr[q].l,l,mid,pos);
else insert(tr[p].r,tr[q].r,mid+1,r,pos);
}
int query(int p,int q,int l,int r,int sum) {
if(l==r) {
int cnt=tr[q].cnt-tr[p].cnt;
int one=(tr[q].sum-tr[p].sum)/cnt;
return (sum+one-1)/one;
}
LL all=tr[q].sum-tr[p].sum;
//cout<<all<<' '<<sum<<endl;
if(all<sum) return -1;
int mid=(l+r)>>1;
LL rs=tr[tr[q].r].sum-tr[tr[p].r].sum;
if(rs>=sum) return query(tr[p].r,tr[q].r,mid+1,r,sum);
else return query(tr[p].l,tr[q].l,l,mid,sum-rs)+tr[tr[q].r].cnt-tr[tr[p].r].cnt;
}
void solve1() {
n=m;
for(int i=1;i<=n;i++) {
int x; scanf("%d",&x);
insert(root[i-1],root[i],1,M,x);
}
while(q--) {
int x,xx,l,r,h; scanf("%d%d%d%d%d",&x,&l,&xx,&r,&h);
int ans=query(root[l-1],root[r],1,M,h);
if(ans==-1) puts("Poor QLW");
else printf("%d\n",ans);
}
}
bool check(int mid,int x1,int y1,int x2,int y2,int h) {
LL sum=f[x2][y2][mid]-f[x1-1][y2][mid]-f[x2][y1-1][mid]+f[x1-1][y1-1][mid];
if(sum<h) return false;
int ans=g[x2][y2][mid+1]-g[x1-1][y2][mid+1]-g[x2][y1-1][mid+1]+g[x1-1][y1-1][mid+1];
h-=f[x2][y2][mid+1]-f[x1-1][y2][mid+1]-f[x2][y1-1][mid+1]+f[x1-1][y1-1][mid+1];
tot=ans+(h+mid-1)/mid;
return true;
}
void solve2() {
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
LL sum1,sum2; sum1=sum2=0;
for(int k=1000;k>=1;k--) {
f[i][j][k]=f[i-1][j][k]+f[i][j-1][k]-f[i-1][j-1][k];
g[i][j][k]=g[i-1][j][k]+g[i][j-1][k]-g[i-1][j-1][k];
if(a[i][j]==k) f[i][j][k]+=k,g[i][j][k]+=1;
}
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
LL sum1,sum2; sum1=sum2=0;
for(int k=1000;k>=1;k--) {
f[i][j][k]+=f[i][j][k+1];
g[i][j][k]+=g[i][j][k+1];
}
}
}
while(q--) {
int x1,y1,x2,y2,h; scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);
int l=1,r=1000,ans=-1; tot=-1;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,x1,y1,x2,y2,h)) ans=mid,l=mid+1;
else r=mid-1;
}
if(ans==-1) puts("Poor QLW");
else printf("%d\n",tot);
}
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%d%d%d",&n,&m,&q);
if(n==1) { solve1(); }
else { solve2(); }
return 0;
}
/*
*/