粟粟的书架题解

粟粟的书架题解

第一次见到这种二合一的题,
开始的时候居然死磕二维主席树,
又是屈辱看题解系列,
其实比较好做
第一部分\(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])

你可能感兴趣的:(粟粟的书架题解)