CF1690G Count the Trains 题解

可能更好的阅读体验

题目传送门

题目大意

有一些车厢在铁轨上按照一定速度向左移动,从左到右编号 1,2,,n。每节车厢的最大速度为 vi。靠左边的车厢以最快的速度前进,右边的车厢速度不能超过左边车厢的速度。定义一节火车为一些前进速度相等的车厢。
现在有 T 个事件,每次第 x 辆车的速度会减小 y,求每次事件发生之后火车的数量。

题目解析

显然我们可以预处理出每节车厢的前进速度,以及火车的数量。
对于每次修改,如果这节车厢的最大速度还是大于等于车厢现在的速度,那么火车节数不变,否则这节火车就会变成两段,同时这节火车右边的一些火车也会被并掉。
我们考虑用数据结构来维护每一节车厢的速度。

方法一:线段树
这种方法比较好想,但是比较难写。
首先不难发现需要维护区间最小值,同时支持找右边第一个小于这辆火车的速度的火车编号,还要支持单点修改。其实就是线段树的传统操作+线段树二分。

方法二:set
显然一节火车是一个区间,把这些区间按照左端点排序插入到一个 set 中,同时记录这节火车的速度。修改的时候直接暴力把所有会被修改的区间删掉,合并,然后插进去。由于每次操作只会最多增加一个区间,并且如果向右查询的区间除了最后一个都会被删除合并,所以复杂度是正确的。

代码(方法二):

void work(){
n=read(); T=read(); int i; for(i=1;i<=n;i++) v[i]=read(); now.l=1; now.v=v[1]; s=E;
for(i=2;i<=n;i++) if(v[i]<now.v){ now.r=i-1; s.insert(now); now.v=v[i]; now.l=i; }
now.r=n; s.insert(now); set<JTZ>::iterator it; while(T--){
x=read(); y=read(); v[x]-=y;
now.l=x; now.v=v[x]; it=s.lower_bound(now);
if(it==s.end()||(*it).l>x) it--;
if((*it).v<=v[x]){ print(s.size()),pc(' '); continue; }
if((*it).l<now.l){
tmp=*it; s.erase(it); if(tmp.l<=x-1) s.insert(mp(tmp.l,x-1,tmp.v));
s.insert(mp(x,tmp.r,tmp.v)); it=s.lower_bound(now);
}
while((*it).v>=now.v){
now.r=(*it).r; s.erase(it); it=s.lower_bound(now);
if(it==s.end()){ now.r=n; break; }
} s.insert(now); print(s.size()),pc(' ');
} pc('\n'); return;
}
posted @   jiangtaizhe001  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示