[HNOI/AHOI2018] 转盘

首先可以发现一定不会停下,因为把停下的时间转化为开头往前挪一步不会使得其他物品的限制变紧

考虑在最后一次经过某个物品时取这个物品,那么枚举终点进行一个时光倒流,断环为链后相当于从 [n+1,2n] 的某个位置出发,一直往前走,使得经过物品 i 的时间 Ti

设终点为 n+p,结束时间为 t,那么限制即 i,t(n+pi)Ti,也就是 t=maxi=1n(Tii+n+p),分离一下得到 t=maxi=1n(Tii)+n+p

但是这个式子其实并不正确,因为断环为链之后前缀 p 到达的时间要加上一个 n,所以说这个前缀内的最大值对 t 的贡献要减去 n

注意到如果序列中的最大值 mx 不在前缀中,那么 p 几乎没有影响,如果在前缀中,答案就是 max(mx,maxi=p+1n(Tii)+n)+p,若要更小就要把后面的最大值也包括到前缀中,那么一个物品能贡献到答案当且仅当其是后缀最大值,可以想到线段树维护单调栈,对所有后缀最大值算出最小的答案,复杂度 O(nlog2n),代码不到 1k

点击查看代码
#include<bits/stdc++.h>
#define inf (int)2e9
#define N 100005
using namespace std;
int read(){
	int w=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
	while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
	return w*h;
}
int n,m,p,ans;
namespace SGT{
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
	int Max[N<<2],Min[N<<2];
	int Bound(int k,int l,int r,int x){
		if(l==r)return Max[k]>x?x+l:inf;
		return Max[rs]>x?min(Min[k],Bound(rs,mid+1,r,x)):Bound(ls,l,mid,x);
	}
	void Modify(int k,int l,int r,int x,int y){
		if(l==r)return void(Max[k]=y-x);
		x<=mid?Modify(ls,l,mid,x,y):Modify(rs,mid+1,r,x,y);
		Max[k]=max(Max[ls],Max[rs]);Min[k]=Bound(ls,l,mid,Max[rs]);
	}
}
using namespace SGT;
signed main(){
	n=read();m=read();p=read();
	for(int i=1;i<=n;i++)Modify(1,1,n,i,read());
	printf("%d\n",ans=Bound(1,1,n,Max[1]-n)+n);
	while(m--){
		int x=read()^(p*ans),y=read()^(p*ans);
		Modify(1,1,n,x,y);
		printf("%d\n",ans=Bound(1,1,n,Max[1]-n)+n);
	}
	return 0;
}
posted @   pidan007  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示