题目链接: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 ;
}

最新文章

  1. MySQL数据迁移到SQL Server
  2. 算法:寻找maximum subarray
  3. .net学习之Session、Cookie、手写Ajax代码以及请求流程
  4. 基于.NET的微软ORM框架视频教程(Entity Framework技术)
  5. Esfog_UnityShader教程_镜面反射SpecularReflection
  6. java8中hashMap
  7. NGINX源代码剖析 之 CPU绑定(CPU亲和性)
  8. dubbo与spring mvc
  9. Servlet(2)
  10. CSS3条件判断——@supports/window.CSS.supports()(转)
  11. Restful随笔
  12. 团队项目beta 汇总
  13. CSS样式命名整理(非原创)
  14. C#基础知识之关键字
  15. information_schema.COLUMNS
  16. Ubuntu14.04设置开机启动脚本(转)
  17. 余额表前后台操作和对应sql
  18. sql 2014 安装失败
  19. Linux读书笔记第三、四章
  20. RPO漏洞学习

热门文章

  1. js 实现淘宝放大镜功能,可更改配置参数 带完整版解析代码[magnifier.js]
  2. Django入门4: ORM 数据库操作
  3. UVA10599:Robots(II)(最长上升子序列)
  4. qemu-img 整理
  5. 接口自动化测试平台-接入持续集成jenkins
  6. Angular 7开发环境配置
  7. 被@ResponseBoby注释的方法在拦截器的posthandle方法中设置cookie失效的问题
  8. POJ 2054 Color a Tree解题报告
  9. 数学--数论--HDU1825(积性函数性质+和函数公式+快速模幂+非互质求逆元)
  10. 在Jetson TX2上捕获、显示摄像头视频