CF1030F题解

1|0CF1030F 题解

传送门  更好的阅读体验


简化题意:有 n 个小球,每个小球在位置 ai,移动一格的代价是 wi,有两种操作,一种是将 wx 改成 y,一种是查询 minx=1n{i=lrwi×(|axai|+|xi|)}

1|1思路


很好的线段树二分练手题。

对于每个询问,首先肯定要找到使得答案最小的 x。我们考虑当前的 x 变成 x+1 时答案的改变量,发现就是 (ax+1ax)×(i=lxwii=x+1rwi),因此 x 取到 [l,r] 的带权中位数时最优,即最小的满足 i=lxwii=x+1rwix

于是就可以直接二分+线段树来找这个 x,这也是其他题解的做法,单次复杂度是 O(log2n) 的。如果直接用线段树二分的话就是 O(logn) 的,感觉还是比较板的。

接下来计算答案比较简单,就不再赘述了。

贴一下线段树二分的代码。

struct Seg{ ll t[N<<2]; inline void upd(int rt){t[rt]=t[ls]+t[rs];} inline void modify(int rt,int l,int r,int x,int k){ if(l==r){ t[rt]=k; return; } if(x<=mid)modify(ls,l,mid,x,k); else modify(rs,mid+1,r,x,k); upd(rt); } inline ll query(int rt,int l,int r,int L,int R){ if(L>R)return 0; if(L<=l&&r<=R)return t[rt]; ll ans=0; if(L<=mid)ans=query(ls,l,mid,L,R); if(mid<R)ans+=query(rs,mid+1,r,L,R); return ans; } inline int query(int rt,int l,int r,int L,int R,ll sum,ll &cur){ if(l==r){ if(2ll*(t[rt]+cur)<sum){ cur+=t[rt]; return -1; } return l; } if(L<=l&&r<=R){ if(2ll*(t[rt]+cur)<sum){ cur+=t[rt]; return -1; } if(2ll*(t[ls]+cur)>=sum)return query(ls,l,mid,L,R,sum,cur); cur+=t[ls]; return query(rs,mid+1,r,L,R,sum,cur); } int ans=-1; if(L<=mid)ans=query(ls,l,mid,L,R,sum,cur); if(~ans)return ans; return query(rs,mid+1,r,L,R,sum,cur); } }T;

__EOF__

本文作者Xttttr
本文链接https://www.cnblogs.com/Xttttr/p/17615939.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Xttttr  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示