题目链接:https://www.luogu.org/problemnew/show/P2468

知识点:  可持久化线段树、二分、前缀和

解题思路:

  对于 \(R, C \le 200, M \le 200,000\) 的数据,先处理出前缀和,然后二分取出的数中最小的数。细节请参考 \(solve2()\) 函数。

  对于 \(R=1,C \le 500,000,M \le 20,000\) 的数据,维护一棵记录 \([1,1000]\) 的数在各个历史版本的个数和相应的总和的可持久化线段树,将一行上各列的数依序更新进去。细节请参考 \(solve2()\) 及相关函数。

AC代码:

 #include <bits/stdc++.h>

 using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int maxc=; int sum[maxc*];//记录总和
int has[maxc*];//记录出现次数
int lson[maxc*],rson[maxc*],T[maxc*];
int tot;
int p1[maxc];
void build(int l,int r,int &rt){
rt=++tot;
sum[rt]=has[rt]=;
if(l==r) return;
int m=(l+r)>>;
build(l,m,lson[rt]);
build(m+,r,rson[rt]);
}
void update(int last,int p,int l,int r,int &rt){
rt=++tot;
lson[rt] = lson[last];
rson[rt] = rson[last];
has[rt] = has[last] + ;
sum[rt] = sum[last] + p;
if (l == r) return;
int m = (l + r) >> ;
if (p <= m) update(lson[last], p, l, m, lson[rt]);
else update(rson[last], p, m + , r, rson[rt]);
}
//用一种类似二分的方式来查询
int query(int s,int t,int h,int l,int r){
int ret=;
while(l<r){
int m=(l+r)>>;
int rch=sum[rson[t]]-sum[rson[s]];//优先用右子树(因为其上的数字较大)
if(rch<h)//如果只用右子树仍然不够,则直接加上右子树的总和,再查询左子树
ret+=has[rson[t]]-has[rson[s]],h-=rch,s=lson[s],t=lson[t],r=m;
else//否则查询右子树
s=rson[s],t=rson[t],l=m+;
}
ret+=(h-)/l+;//答案修正
return ret;
}
void solve1(int R,int C,int M){
build(,,T[]);
for(int i=;i<=C;i++){
scanf("%d",&p1[i]);
update(T[i-],p1[i],,,T[i]);
}
int x1,y1,x2,y2,h;
for(int i=;i<M;i++){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);
if(sum[T[y2]]-sum[T[y1-]]<h) printf("Poor QLW\n");
else
printf("%d\n",query(T[y1-],T[y2],h,,));
}
} int p[][];
int have[][][];//have[x][y][k]: 代表p矩阵中在点(x,y)左上角的子矩阵里大于等于k的数的个数
int height[][][];//height[x][y][k]: 代表p矩阵中在点(x,y)左上角的子矩阵里大于等于k的数的总和
int get_have(int x1,int y1,int x2,int y2,int ind){
return have[x2][y2][ind]-have[x1][y2][ind]-have[x2][y1][ind]+have[x1][y1][ind];
}
int get_height(int x1,int y1,int x2,int y2,int ind){
return height[x2][y2][ind]-height[x1][y2][ind]-height[x2][y1][ind]+height[x1][y1][ind];
}
void solve2(int R,int C,int M){
for(int i=;i<=R;i++){
for(int j=;j<=C;j++)
scanf("%d",&p[i][j]);
}
for(int i=;i>=;i--){
for(int x=;x<=R;x++){
for(int y=;y<=C;y++){
//转移
height[x][y][i]=height[x-][y][i]+height[x][y-][i]-height[x-][y-][i]+(p[x][y]>=i?p[x][y]:);
have[x][y][i]=have[x-][y][i]+have[x][y-][i]-have[x-][y-][i]+(p[x][y]>=i?:);
}
}
}
int x1,y1,x2,y2;
int h;
while(M--){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);
int l=,r=;//二分取出来的数中最小的数,此处 r 如果没有初始化为 1001 的话会 WA 一个点
int ans=-;
for(int i=;i<;i++){
int m=(l+r)>>;
int tmp=get_height(x1-,y1-,x2,y2,m);
if(tmp>=h)
l=m,ans=get_have(x1-,y1-,x2,y2,m)-(tmp-h)/m;//减掉多余的部分
else
r=m;
}
if(ans==-) printf("Poor QLW\n");
else printf("%d\n",ans);
}
} int main(){
// freopen("in.txt","r",stdin);
int R,C,M;
scanf("%d%d%d",&R,&C,&M);
if(R==) solve1(R,C,M);
else solve2(R,C,M);
return ;
}

洛谷P2468 粟粟的书架的更多相关文章

  1. 洛谷P2468 [SDOI2010]粟粟的书架

    来了来了,随便拽一道题写题解[大雾] 最近发现自己基础奇差于是开始复习之前学过的东西,正好主席树我几乎完全没学会,然后打开洛谷试炼场… 发现了这么一道二合一的题. 这道题其实分成两个部分,前50%是一 ...

  2. 洛谷P2468 [SDOI2010]粟粟的书架(二分答案 前缀和 主席树)

    题意 题目链接 给出一个矩形,每个点都有一些值,每次询问一个子矩阵最少需要拿几个数才能构成给出的值 Sol 这题是真坑啊.. 首先出题人强行把两个题拼到了一起, 对于前$50 \%$的数据,考虑二分答 ...

  3. 洛谷P2468 SDOI 2010 粟粟的书架

    题意:给你一个矩形书架,每个点是这本书的页数,每次询问(x1,y1)(x2,y2)这个小矩形里最少需要取几本书使得页数和等于Hi. 题解:小数据二位前缀和预处理+二分答案,大数据一行所以用主席树做,感 ...

  4. 洛咕 P2468 [SDOI2010]粟粟的书架

    强行二合一啊... 前面直接二分最小值,二维前缀和.后面用主席树查最小值.注意要写\(nlogn\). // luogu-judger-enable-o2 #include<bits/stdc+ ...

  5. 洛谷$P$2468 粟粟的书架 $[SDOI2010]$ 主席树

    正解:主席树 解题报告: 传送门! 题目大意是说,给定一个矩形,然后每次会给一个,这个大矩形中的一个小矩形,询问从小矩形中最少选多少个数字能满足它们之和大于等于给定数字$x$ 看起来很神的样子,完全不 ...

  6. 洛谷 题解 P2676 【超级书架】

    题解 P2676 [超级书架] 这题就只是一个从大到小的排序而已,用"sort"函数 再用"while"判断奶牛塔的高度是否比书架高度要高 送上代码: #inc ...

  7. BZOJ1926:[SDOI2010]粟粟的书架——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1926 https://www.luogu.org/problemnew/show/P2468 幸福幼 ...

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

    1926: [Sdoi2010]粟粟的书架 Time Limit: 30 Sec  Memory Limit: 552 MBSubmit: 616  Solved: 238[Submit][Statu ...

  9. 【BZOJ1926】粟粟的书架(主席树,前缀和)

    [BZOJ1926]粟粟的书架(主席树,前缀和) 题面 Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Co ...

随机推荐

  1. 我对sessionid的理解

    不知道是不是扯蛋,还是太菜... 看上面的的话毫不关系是吧...自己看过一点 关于 说session id 的 一些文章, 貌似都是一样的....以下内容个人理解, 请大家指正... 我想自己举个例子 ...

  2. 数学--数论--HDU 1098 Ignatius's puzzle (费马小定理+打表)

    Ignatius's puzzle Problem Description Ignatius is poor at math,he falls across a puzzle problem,so h ...

  3. CodeForces-1058B B. Vasya and Cornfield

    这题,我真的不知道题解是啥,自己看代码吧. #include<iostream> using namespace std; int main() { int n, d,m,i,x,y; c ...

  4. css的属性选择器

    语法说明: 属性选择器需要将对应属性放入到 方括号中  [ ] ,其中包含属性名,标识符(* $ ~ ^ |) 使用说明: [attribute] 例如  [target] 表示 选择带有 targe ...

  5. schedule定时任务出现问题 (大坑已填)!!

    因为python每次运行完,并不清除内存,nowtime一直不变,这导致了一个致命问题,使我的脚本一直运行失败,具体如下: 我设置的是每隔30分钟登陆一次,代码如下 if __name__ == &q ...

  6. Xenia and Colorful Gems(二分--思维)

    给定三个数组a,b,c. 要求从每个数字取一个数,使得两两之差和最小. 求出这个数. \(我又懵逼了.我是会O(n^3)的暴力啊,怎么办.\) \(\color{Red}{从结果看,选出来的三个数必定 ...

  7. node能做的性能优化

    开发中,我们就离不开性能优化,那么在使用node开发的时候,我们可以使用那些代码来优化性能呢 一.释放内存 当node运行检测到错误的时候,释放掉内存 http.get(str,(res)=>{ ...

  8. PrintStream:打印流

    package com.itheima.demo05.PrintStream; import java.io.FileNotFoundException; import java.io.PrintSt ...

  9. [hdu5247]rmq+预处理

    题意:有一个无序数组,求有多少个长度为k的区间满足把区间内的数排序后是连续的. 思路:长度为k的区间排序后是 连续的数等价于maxval-minval等于k-1并且不同的数有k个(或者说没有相同的数) ...

  10. Python实现将网站域名解析为ip地址

    起因 因为一些事情,需要将域名解析为ip地址,想到Python作为万能语言,就用Python来实现这个功能 代码 import socket url = 'shiyixirui.cn' res = s ...