粟粟的书架题解
第一次见到这种二合一的题,
开始的时候居然死磕二维主席树,
又是屈辱看题解系列,
其实很比较好做
第一部分\(R, C≤200,M≤200000,1≤Pi,j≤1,000\)
这一部分可以用两个数组来记录:
\(num[i][j][k]\):代表1~i,1~j的矩形中小于等于k的书页数量,
\(v[i][j][k]\):代表1~i,1~j的矩形中小于等于k的书页页数之和。
二分最大书页页数,找到满足矩阵内v值大于给定h的最小值,输出对应num,
预处理时用二维前缀和的方式维护即可,
bool check(int x){return v[t3][t4][x]-v[t1-1][t4][x]+v[t1-1][t2-1][x]-v[t3][t2-1][x]>=t5;}
int ef(int l,int r){
if(l==r) return l;
int mid=(l+r+1)>>1;
if(check(mid)) return ef(mid,r);
return ef(l,mid-1);
int main(){
if(r!=1){
for(int i=1;i<=r;++i) for(int j=1;j<=c;++j){t=read(); for(int k=1;k<=1000;++k) num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(t>=k),v[i][j][k]=v[i-1][j][k]+v[i][j-1][k]-v[i-1][j-1][k]+(t>=k?t:0);}
for(int i=1;i<=m;++i){t1=read(),t2=read(),t3=read(),t4=read(),t5=read(); if(!check(1)){printf("Poor QLW\n"); continue;} t=ef(1,1000),p=num[t3][t4][t+1]-num[t1-1][t4][t+1]+num[t1-1][t2-1][t+1]-num[t3][t2-1][t+1],q=v[t3][t4][t+1]-v[t1-1][t4][t+1]+v[t1-1][t2-1][t+1]-v[t3][t2-1][t+1],printf("%d\n",p+(t5-q-1)/t+1);}
}
}
}
后面r=1的情况:
同样二分,不过是二分第k大的书页页数的k,
我们可以用主席树维护第k大的页数之和,
直接上总代码吧:
#include
#define ll long long
using namespace std;
const int N=5e5+3006,K=202,M=1002;
int m,r,c,t,l=0,t1,t2,t3,t4,t5,num[K][K][M],v[K][K][M],p,q,cnt=0,rt[N],sum[N*12],son[N*12][2];
ll w[N<<4];
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
void update(int l,int r,int k,int &x,int y){
if(!x) x=++cnt;
if(l==r){sum[x]=sum[y]+1,w[x]=w[y]+l; return;}
int mid=l+r>>1;
if(k<=mid) update(l,mid,k,son[x][0],son[y][0]),son[x][1]=son[y][1];
else update(mid+1,r,k,son[x][1],son[y][1]),son[x][0]=son[y][0];
sum[x]=sum[son[x][0]]+sum[son[x][1]],w[x]=w[son[x][0]]+w[son[x][1]];
}
int query(int l,int r,int k,int x,int y){
if(l==r) return min(sum[x]-sum[y],k)*l;
int mid=l+r>>1;
if(k<=sum[son[x][1]]-sum[son[y][1]]) return query(mid+1,r,k,son[x][1],son[y][1]);
return w[son[x][1]]-w[son[y][1]]+query(l,mid,k-sum[son[x][1]]+sum[son[y][1]],son[x][0],son[y][0]);
}
bool check(int x){return v[t3][t4][x]-v[t1-1][t4][x]+v[t1-1][t2-1][x]-v[t3][t2-1][x]>=t5;}
int ef(int l,int r){
if(l==r) return l;
int mid=(l+r+1)>>1;
if(check(mid)) return ef(mid,r);
return ef(l,mid-1);
}
int ef2(int l,int r){
if(l==r) return l;
int mid=l+r>>1;
if(query(1,1000,mid,rt[t4],rt[t2-1])>=t5) return ef2(l,mid);
return ef2(mid+1,r);
}
int main(){
r=read(),c=read(),m=read(),rt[0]=++cnt;
if(r!=1){
for(int i=1;i<=r;++i) for(int j=1;j<=c;++j){t=read(); for(int k=1;k<=1000;++k) num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(t>=k),v[i][j][k]=v[i-1][j][k]+v[i][j-1][k]-v[i-1][j-1][k]+(t>=k?t:0);}
for(int i=1;i<=m;++i){t1=read(),t2=read(),t3=read(),t4=read(),t5=read(); if(!check(1)){printf("Poor QLW\n"); continue;} t=ef(1,1000),p=num[t3][t4][t+1]-num[t1-1][t4][t+1]+num[t1-1][t2-1][t+1]-num[t3][t2-1][t+1],q=v[t3][t4][t+1]-v[t1-1][t4][t+1]+v[t1-1][t2-1][t+1]-v[t3][t2-1][t+1],printf("%d\n",p+(t5-q-1)/t+1);}
}
else{
for(int i=1;i<=c;++i) t=read(),update(1,1000,t,rt[i],rt[i-1]);
for(int i=1;i<=m;++i){t1=read(),t2=read(),t3=read(),t4=read(),t5=read(); if(query(1,1000,t4-t2+1,rt[t4],rt[t2-1])