CF1690G Count the Trains 题解
题目大意
有一些车厢在铁轨上按照一定速度向左移动,从左到右编号 。每节车厢的最大速度为 。靠左边的车厢以最快的速度前进,右边的车厢速度不能超过左边车厢的速度。定义一节火车为一些前进速度相等的车厢。
现在有 个事件,每次第 辆车的速度会减小 ,求每次事件发生之后火车的数量。
题目解析
显然我们可以预处理出每节车厢的前进速度,以及火车的数量。
对于每次修改,如果这节车厢的最大速度还是大于等于车厢现在的速度,那么火车节数不变,否则这节火车就会变成两段,同时这节火车右边的一些火车也会被并掉。
我们考虑用数据结构来维护每一节车厢的速度。
方法一:线段树
这种方法比较好想,但是比较难写。
首先不难发现需要维护区间最小值,同时支持找右边第一个小于这辆火车的速度的火车编号,还要支持单点修改。其实就是线段树的传统操作+线段树二分。
方法二: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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具