题目链接: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. KVM 一键批量创建虚拟机

    目录 一.原理 二.基础镜像 2.1.创建基础镜像 2.2. 完善基础镜像 2.3.基础镜像设置权限 3.4 设置 title 3.5.基础镜像XML 三.批量创建机器脚本 四.挂载磁盘多种方式 4. ...

  2. 安装并使用pyecharts库

    在cmd命令行中输入安装命令, pyecharts库的安装命令如下: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyecharts ...

  3. POJ1651:Multiplication Puzzle(区间dp)

    Multiplication Puzzle Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9419 Accepted: 5850 ...

  4. require.context的妙用

    比较好用,记录下来. 以下方法将获取vuex中Modules文件夹里的所有modules并导出. const files = require.context(".", false, ...

  5. python笔记 函数初识

    1. 函数: 封装一个功能 def    my_len(形参):          ->  def  声明定义一个函数   my_len 函数名命名规则同变量 ······          - ...

  6. CF思维联系– Codeforces-987C - Three displays ( 动态规划)

    ACM思维题训练集合 It is the middle of 2018 and Maria Stepanovna, who lives outside Krasnokamensk (a town in ...

  7. 无向图求割(找桥)tarjan

    本博客参考了李煜东的<算法竞赛进阶指南>,大家要是觉得这篇文章写的不错请大家支持正版.豆瓣图书 我在之前的博客中讲解了搜索序时间戳,这次我们讲讲追溯值的概念. 追溯值: 设subtree( ...

  8. 题解 AT3849 【[ABC084C] Special Trains】

    本文为UserUnknown原创 题目大意 总共有 \(N\) 个车站,每两个相邻的车站有单向的车. 从第 \(i\) 个站到第 \(i+1\) 个站 需要时间 \(C_i\) 分钟,且第一趟车在 \ ...

  9. andorid jar/库源码解析之EventBus

    目录:andorid jar/库源码解析 EventBus: 作用: 用于不同Activity,Service等之间传递消息(数据). 栗子: A页面:onCreate定义   EventBus.ge ...

  10. golang之channel

    Buffered Channels package main import "fmt" func main() { ch := make(chan int, 2) ch <- ...