SDOI2010 粟粟的书架 lg2468(可持久化,前缀和)

题面见https://www.luogu.org/problemnew/show/P2468

然后这道题属于合二为一题,看一眼数据范围就能发现

首先我们先考虑50分,二维前缀和维护一下(反正我不记得公式,手推了半天)

tot[i][j][k]表示矩阵(1,1)到(i,j)中数值大等于k的总和

num[i][j][k]表示矩阵(1,1)到(i,j)中数值大等于k的个数

那么做法也就显而易见了,二分k的值进行check

最后注意一个小问题,就是有可能一个k值有多个点,而我不需要全选就能满足条件,这个可以自行理解一下

后百分之五十,一开始口胡了一个一维前缀和的做法,貌似是两个log,然而我在学可持久化数据结构,不能偷懒

思考了一下,开一棵权值线段树,把它变成主席树,根x代表插入了第x个数后的情况

然后建树,更新都是裸的操作

关于查询我的想法我写在了代码里,想不通的可以看一下

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘) f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        w=(w<<3)+(w<<1)+ch-48;
        ch=getchar();
    }
    return w*f;
}
int n,m,q,a[210][210],tot[210][210][1010],num[210][210][1010],ans,cnt,root[5000010],b[5000010];
int get_sum(int x1,int y1,int x2,int y2,int k,int f)
{
    if(f==1)return tot[x2][y2][k]-tot[x2][y1-1][k]-tot[x1-1][y2][k]+tot[x1-1][y1-1][k];
    else return num[x2][y2][k]-num[x2][y1-1][k]-num[x1-1][y2][k]+num[x1-1][y1-1][k];
}
inline void work2(){//二维前缀和大力维护,口胡了一下写在上面了,就不多解释了,着重看主席树
    int i,j,k,maxx=0;
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            a[i][j]=read();maxx=max(maxx,a[i][j]);
        }
    }
    for(k=0;k<=maxx;k++){
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                tot[i][j][k]=tot[i-1][j][k]+tot[i][j-1][k]-tot[i-1][j-1][k]+(a[i][j]>=k)*a[i][j];
                num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(a[i][j]>=k);
            }
        }
    }
    while(q--){
        int x1,y1,x2,y2,h;
        x1=read();y1=read();x2=read();y2=read();h=read();
        if(get_sum(x1,y1,x2,y2,0,1)<h) puts("Poor QLW");
        else{
            int l=0,r=maxx+1;ans=-1;
            while(l<=r){
                int mid=(l+r)>>1;
                if(get_sum(x1,y1,x2,y2,mid,1)>=h){
                    ans=mid;l=mid+1;
                }
                else r=mid-1;
            }
            printf("%d\n",get_sum(x1,y1,x2,y2,ans,2)-(get_sum(x1,y1,x2,y2,ans,1)-h)/ans);
        }
    }
}
struct Node{
    int ls,rs,sum,size;
}st[50000010];
inline int build(int l,int r){
    int pos=cnt++;
    if(l==r) return pos;
    int mid=(l+r)>>1;
    st[pos].ls=build(l,mid);
    st[pos].rs=build(mid+1,r);
    return pos;
}//常规建树
inline int update(int tim,int l,int r,int x){//tim表示历史版本,l,r为范围,x为我当前插入的数
    int pos=cnt++;
    st[pos]=st[tim];st[pos].size++;st[pos].sum+=x;//这个节点的size+1,sum+=x
    if(l==r) return pos;//到叶子了,大力返回就好
    int mid=(l+r)>>1;
    if(x<=mid) st[pos].ls=update(st[tim].ls,l,mid,x);
    else st[pos].rs=update(st[tim].rs,mid+1,r,x);
    return pos;
}
inline int query(int l,int r,int fir,int sec,int w){//具体解释见下方
    if(l==r) return (w-1)/l+1;//可能不会整除,就这么处理一下就好了
    int mid=(l+r)>>1;int x=st[st[sec].rs].sum-st[st[fir].rs].sum;
    if(w<=x) return query(mid+1,r,st[fir].rs,st[sec].rs,w);
    else return st[st[sec].rs].size-st[st[fir].rs].size+query(l,mid,st[fir].ls,st[sec].ls,w-x);
}
/*
这棵主席树是基于权值线段树的,权值的范围只有1k
主席树维护了历史版本的权值线段树上的size和sum
然后关于建树和更新都没什么新意
查询这个我一开始不能很好的理解,那么我现在稍微解释一下我的思路
首先l,r,fir,sec,w分别表示区间,版本号,还需要多少值
然后大多数题查询的时候都是向左子树查一下,比一下大小
这里查右子树是因为这是一棵权值线段树,我们希望尽量少地选点,也就意味着选的数要尽可能大
那么能选右子树(也就是值更大的点),当然选大的啊
如果右子树总和够,就往右子树走,不够的话,算上右子树,往左子树走
*/
inline void work1()
{
    int maxw=-1e9-7;
    for(int i=1;i<=m;i++) b[i]=read(),maxw=max(b[i],maxw);
    root[0]=build(1,maxw+10);
    for(int i=1;i<=m;i++) root[i]=update(root[i-1],1,maxw,b[i]);
    for(int i=1;i<=q;i++)
    {
        int y1,y2,h;y1=read(),y1=root[read()-1],y2=read(),y2=root[read()],h=read();
        if(st[y2].sum-st[y1].sum<h){puts("Poor QLW");continue;}
        printf("%d\n",query(1,maxw,y1,y2,h));
    }
}
int main(){
    n=read();m=read();q=read();
    if(n!=1){//合二为一辣鸡题
        work2();
    }
    else work1();
    return 0;
}

原文地址:https://www.cnblogs.com/wenci/p/10158661.html

时间: 2024-10-13 01:41:23

SDOI2010 粟粟的书架 lg2468(可持久化,前缀和)的相关文章

1926: [Sdoi2010]粟粟的书架

1926: [Sdoi2010]粟粟的书架 Time Limit: 30 Sec  Memory Limit: 552 MBSubmit: 807  Solved: 321[Submit][Status][Discuss] Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Co rmen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列 摆放的书有Pi,j

[SDOI2010]粟粟的书架 [主席树]

[SDOI2010]粟粟的书架 考虑暴力怎么做 显然是提取出来 (x2-x1+1)*(y2-y1+1) 个数字拿出来 然后从大到小排序 然后就可以按次取数了- 然而接下来看数据范围 \(50\%\ r,c\leq 200\) \(50\%\ r=1,c\leq 5*10^5\) 值域 \(\in [1,1000]\) 对于前 50% 可以用个前缀和搞定- 令 \(sum_{i,j,k}\) 为 大于 k 的前缀和 \(num_{i,j,k}\) 为 大于 k 的前缀和数量 然后愉快的二分? 另外

【BZOJ1926】【SDOI2010】粟粟的书架 [主席树]

粟粟的书架 Time Limit: 30 Sec  Memory Limit: 552 MB[Submit][Status][Discuss] Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章. 粟粟家中有一个 R行C列 的巨型书架,书架的每一个位置都摆有一本书,上数第 i 行.左数第 j 列摆放的书有Pi,j页厚. 粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取

bzoj1926 [Sdoi2010]粟粟的书架

Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚下放上几本书,就可以够着苹果:她同时注意到

BZOJ1926 [Sdoi2010]粟粟的书架 【主席树 + 二分 + 前缀和】

题目 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Co rmen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列 摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的 苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚 下放上几本书,就可以够着苹果:她同时注意到,对于第

【刷题】BZOJ 1926 [Sdoi2010]粟粟的书架

Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚下放上几本书,就可以够着苹果:她同时注意到

[Sdoi2010]粟粟的书架

Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚下放上几本书,就可以够着苹果:她同时注意到

【BZOJ-1926】粟粟的书架 二分 + 前缀和 + 主席树

1926: [Sdoi2010]粟粟的书架 Time Limit: 30 Sec  Memory Limit: 552 MBSubmit: 616  Solved: 238[Submit][Status][Discuss] Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列摆放的书有Pi,j页厚

粟粟的书架题解

粟粟的书架题解 第一次见到这种二合一的题, 开始的时候居然死磕二维主席树, 又是屈辱看题解系列, 其实很比较好做 第一部分\(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, 预处理时用二维前缀和的方式维护即可