把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解 P6544 [CEOI2014] Cake

洛谷

题意

一共 n 个蛋糕,每个蛋糕用有一个权值 di,会从某一个开始,吃两端权值更小的那个蛋糕。
q 个操作,分为两种:

  1. 修改,将编号为 i 的蛋糕升为第 e 美味的,保证一定是提高排名。
  2. 查询,询问在吃掉编号为 b 的蛋糕前会吃掉多少蛋糕。

    e10n2.5×105q5×105

先划一下重点:e10,并且是提升至 e 这个排名。

分析

重新分析一下题目让我们做一些什么事,我们需要从我们的起始点开始,直到吃到指定点,再吃到指定点的过程中,我们必然吃到从指定点到起始点这一整块上的所有店,那也就代表,要么我们一边吃到了底,否则,就是在那一段有一个比我们这个路径都要大的点。

简单来说,我们的另一端是一个大于我们起始点至结束点最大值的点。

这是我们的查询操作,很明显满足二分性质,只要我们运用前缀和或者区间查询,就可以以 O(logn) 的时间复杂度解决。

由于起始点与终点的位置关系,因此要分类,此处只贴一边,另一边相近。

inline int queryl(int id) {
int x=tree.query(1,1,n,id,be-1),l=be+1,r=n,res=n+1;
while(l<=r) {
int mid=l+r>>1;
int num=tree.query(1,1,n,be+1,mid);
if(num>x) {
res=mid;
r=mid-1;
} else l=mid+1;
}
return res;
}

接下来,我们的重点就到了修改上,这个修改很不同寻常,一般的修改应该是修改一个值,而此处却是修改到一个排名。

暴力

为了方便表述,坐标为 id

我们的 di 两两不同并且 din,因此,我们的 d 就是一个排列,那么我们只需要将所有值在 did 与第 e 个之间的 d 下降,然后再将 id 顶上即可。
时间复杂度 O(n),配合暴力的查询可以拿下 15,配合 O(logn) 的查询可以再拿下 20。

int id=read(),x=read();
for(int j=1;j<=n;++j) if(a[j]>=x&&a[j]<a[id]) ++a[j];
a[id]=x;
tree.build(1,1,n);

正解

我们观察一下我们的查询操作,我们并不需要值的大小,而是需要值的大小关系,我们需要的序列并不一定是一个排列,只要大小关系,排名不变即可。

我们再观察一下我们这个非常优秀的性质 e10,这个性质题目的一个约束条件。

我们修改了比我们要修改的更小的值,那我们是不是也可以修改更大的值,而且非常巧啊,我们的这些更大值只要 10 个呢。

我们讲前十大的记录,在修改时,将小于 e 的全部 +1,修改当前点的值,重新维护前十小即可。

int id=read(),x=read();
int num=b[x].num-1;
for(int i=1; i<x; ++i) tree.change(1,1,n,b[i].id,b[i].num-1),b[i].num--;
tree.change(1,1,n,id,num);
int flag=cnt+1;
for(int i=1; i<=cnt; ++i) if(b[i].id==id) flag=i;
b[flag]=<%num,id%>;
if(flag<cnt+1) sort(b+1,b+cnt+1);
else sort(b+1,b+cnt+2);

总结一下,我们此题的问题并不是数据结构的难度,而是发掘题目的性质,并合理利用,解决即可。

posted @   djh0314  阅读(30)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示