bzoj 5286
极其神的一道题
首先看到:环上问题并不好做,所以我们按套路拆环之后扔到序列上
接下来,我们来分析一下这个游戏的最优策略
最优策略一般有两种表述,这里一并给出
①:在原地等到某一个时间点从某一个起点开始走,不停留地恰好走完一圈达到结束,取所有可行方案中最小值
②:从某一个点为起点开始走,对每个点如果没到时间就等到时间往下走,走完一圈结束,取所有可行方案中最小值
这两个表述可以证明是等价的(你证一个)因此我们采用第一种表述(主要是为了推式子方便)
首先无论从哪一个点开始走,我们都保证只走一圈,因此走圈的代价是固定的
于是问题被转化成了求从某一个点开始要等的最小时间
那么我们把这个最小时间的表达式列出来:
设当前是第号点,那么要等的最小时间即为
于是我们只需求出这个最大值即可
每求一次是的,时间复杂度不够优秀,因此我们需要考虑数据结构维护
这里需要一点前置知识,如果你没有做过bzoj 2957的话应该先做一下这道题或者至少看一下这里
现在假设这些你都会了
接下来进行一些神奇的变化:
不难发现,这个表达式与无关,因此我们考虑维护他
设,那么原式即化成
那么,对于每一个确定的,我们只需找出一个最小的与之对应即可
这是个好问题,怎么找?
首先我们要注意到,这里的值是要求取最大的,同时要求,因此我们需要维护的是后缀最大值
那么,借助那道题的思想,我们在每次维护时仍然分左右区间计算,只不过这次是右区间影响左区间
我们用右区间的最大值作为限制,要求左区间中选取最大值大于右区间者进行更新,最后注意算出的是代价,取最小值即可
什么?为什么右区间的贡献不继承上来?
因为右半部分是我复制出来的,起点要求在左半部分里
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define rt1 rt<<1 #define rt2 (rt<<1)|1 using namespace std; const int inf=0x3f3f3f3f; struct Seg_tree { int maxh; int maxlen; }tree[800005]; int a[200005]; int n,m,p; int pushup(int rt,int l,int r,int lim) { if(l==r) { if(tree[rt].maxh<=lim)return inf; return lim+l+1; } int mid=(l+r)>>1; if(tree[rt2].maxh<=lim)return pushup(rt1,l,mid,lim); return min(tree[rt].maxlen,pushup(rt2,mid+1,r,lim)); } void buildtree(int rt,int l,int r) { if(l==r) { tree[rt].maxh=a[l]-l; return; } int mid=(l+r)>>1; buildtree(rt1,l,mid),buildtree(rt2,mid+1,r); tree[rt].maxh=max(tree[rt1].maxh,tree[rt2].maxh); tree[rt].maxlen=pushup(rt1,l,mid,tree[rt2].maxh); } void update(int rt,int l,int r,int posi) { if(l==r) { tree[rt].maxh=a[l]-l; return; } int mid=(l+r)>>1; if(posi<=mid)update(rt1,l,mid,posi); else update(rt2,mid+1,r,posi); tree[rt].maxh=max(tree[rt1].maxh,tree[rt2].maxh); tree[rt].maxlen=pushup(rt1,l,mid,tree[rt2].maxh); } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i]; n<<=1; buildtree(1,1,n); int lastans=min(tree[1].maxlen,tree[1].maxh+1)+n/2-1; printf("%d\n",lastans); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if(p)x^=lastans,y^=lastans; a[x]=y,a[x+n/2]=y; update(1,1,n,x),update(1,1,n,x+n/2); lastans=tree[1].maxlen+n/2-1; printf("%d\n",lastans); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY