明顯的二合一問題。貪心的想,要個數最少,那麼久從頁數多的開始選。於是對於前50%的數據,可以直接預處理(1~x,1~y)矩陣內大於等於k的元素個數、元素之和的首碼和,然後二分k值來驗證;對於後50%的數據,已經退化為一維情形,若再使用前面的方法會mle(5e5 1e3 4),那麼考慮使用主席樹來維護 ...
明顯的二合一問題。貪心的想,要個數最少,那麼久從頁數多的開始選。於是對於前50%的數據,可以直接預處理(1~x,1~y)矩陣內大於等於k的元素個數、元素之和的首碼和,然後二分k值來驗證;對於後50%的數據,已經退化為一維情形,若再使用前面的方法會mle(5e51e34),那麼考慮使用主席樹來維護:每個節點建一棵權值線段樹,查詢時區間內優先選擇有區間即可。
可知兩種方法的時間複雜度都是O(Qlog1000)
#include <bits/stdc++.h>
using namespace std;
int n,m,q;
namespace sofeerDure {
const int N=207;
int p[201][201];
int f[1001][201][201];
int g[1001][201][201];
#define sum (f[mid][c][d]-f[mid][a-1][d]-f[mid][c][b-1]+f[mid][a-1][b-1])
#define num (g[mid][c][d]-g[mid][a-1][d]-g[mid][c][b-1]+g[mid][a-1][b-1])
static void main() {
for(int i=1; i<=n; ++i) {
for(int j=1; j<=m; ++j) {
scanf("%d",&p[i][j]);
}
}
for(int k=1; k<=1000; ++k) {
for(int i=1; i<=n; ++i) {
for(int j=1; j<=m; ++j) {
f[k][i][j]=f[k][i-1][j]+f[k][i][j-1]-f[k][i-1][j-1];
g[k][i][j]=g[k][i-1][j]+g[k][i][j-1]-g[k][i-1][j-1];
if(p[i][j]>=k) f[k][i][j]+=p[i][j], g[k][i][j]++;
}
}
}
for(int a,b,c,d,h; q--; ) {
scanf("%d%d%d%d%d",&a,&b,&c,&d,&h);
int l=1,r=1000,mid,ans=-1;
while(l<=r) {
mid=(l+r)>>1;
if(sum>=h) ans=mid, l=mid+1;
else r=mid-1;
}
if((mid=ans)<0) puts("Poor QLW");
else printf("%d\n",num-(sum-h)/mid);
}
}
#undef sum
#undef num
}
namespace haibaraDure {
const int N=5e5+10;
struct Node {
int ls,rs,sum,num;
} t[N*20];
int root[N],tot;
int build(int l,int r) {
int x=++tot;
if(l==r) return x;
int mid=(l+r)>>1;
t[x].ls=build(l,mid);
t[x].rs=build(mid+1,r);
return x;
}
int insert(int x,int l,int r,int p) {
int y=++tot;
t[y]=t[x];
t[y].sum+=p;
t[y].num++;
if(l==r) return y;
int mid=(l+r)>>1;
if(p<=mid) t[y].ls=insert(t[x].ls,l,mid,p);
else t[y].rs=insert(t[x].rs,mid+1,r,p);
return y;
}
int query(int x,int y,int l,int r,int k) {
if(l==r) return (k-1)/l+1;
int mid=(l+r)>>1;
int dif=t[t[y].rs].sum-t[t[x].rs].sum;
if(k<=dif) return query(t[x].rs,t[y].rs,mid+1,r,k);
else return query(t[x].ls,t[y].ls,l,mid,k-dif)+t[t[y].rs].num-t[t[x].rs].num;
}
static void main() {
root[0]=build(1,1000);
for(int i=1,x; i<=m; ++i) {
scanf("%d",&x);
root[i]=insert(root[i-1],1,1000,x);
}
for(int a,b,c,d,h; q--; ) {
scanf("%d%d%d%d%d",&a,&b,&c,&d,&h);
if(t[root[d]].sum-t[root[b-1]].sum<h) puts("Poor QLW");
else printf("%d\n", query(root[b-1],root[d],1,1000,h));
}
}
}
int main() {
scanf("%d%d%d",&n,&m,&q);
if(n>1) sofeerDure::main();
else haibaraDure::main();
return 0;
}