luogu P4425 [HNOI/AHOI2018]转盘
题面传送门
首先发现这个东西又可以走又可以不走很难受,所以考虑推一点性质。
我们不妨将整个过程倒过来,改成从终点向起点走。
容易发现我们至少要绕一圈,但是绕了一圈之后再走的路就没有意义了因为之后一定要再走一遍,所以可以看做在起点等了一段时间一直走到终点。
断环为链之后不难发现我们要求的东西长这个样子:。
因为,所以,上面这个式子可以改写成一个后缀的形式:
发现这个形式很像楼房重建,那么就用线段树维护一个单调栈就好了,时间复杂度
什么,你不会线段树维护单调栈?
对于一个节点在update的时候,计算这个区间内的单调栈长度,右区间的答案是一定会在这个节点的答案中的,而左区间需要递归处理,观察左区间的右区间,如果左区间的右区间大于当前节点右区间最大值,那么左区间的左区间一定在答案中,如果小于,那么左区间的右区间一定不在答案中,所以每次只有单侧递归,时间复杂度
这题只要维护这个单调栈首尾是啥然后合并一下就好了,因为答案只能在后缀max对应节点上取到。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (5000000-5)
#define K (1500+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;const int I1=1e8,I2=1e9;
int n,m,p,La,k,x,y,z,A[N<<1];
/*I int GA(){
int i,Ans=1e9,Ns=-1e9;for(i=n+1;i<=2*n;i++) Ns=max(Ns,A[i]);
for(i=n;i;i--) Ns=max(Ns,A[i]),Ans=min(Ans,Ns+i+n-1);return Ans;
}*/
struct Pa{int l,r,f;Pa operator +(const Pa &B)const{if(B.f>=I2) return (Pa){l,r,f};return (Pa){l,B.r,min(min(B.f,f),A[r]+(B.l>=n?I2:B.l+1)+n-1)};};};
namespace Tree{
#define ls now<<1
#define rs now<<1|1
Pa F[N<<3],G[N<<3];I Pa UD(int x,int l,int r,int now){if(l==r)return (Pa){l,l,A[l]>=x?I1:I2};int m=l+r>>1;return A[F[rs].r]>=x?UD(x,m+1,r,rs)+G[now]:UD(x,l,m,ls);}
I void Up(int now,int l,int r){G[now]=UD(A[F[rs].r],l,l+r>>1,ls);F[now]=F[rs]+G[now];}
I void BD(int l=0,int r=2*n,int now=1){if(l==r) {F[now]=(Pa){l,l,I1};return;}int m=l+r>>1;BD(l,m,ls);BD(m+1 ,r,rs);Up(now,l,r);}
I void Ins(int x,int l=0,int r=2*n,int now=1){if(l==r) return;int m=l+r>>1;x<=m?Ins(x,l,m,ls):Ins(x,m+1,r,rs);Up(now,l,r);}
#undef ls
#undef rs
}
int main(){
freopen("1.in","r",stdin);
int i;scanf("%d%d%d",&n,&m,&p);A[0]=1e9;for(i=1;i<=n;i++) scanf("%d",&A[i]),A[i+n]=A[i];for(i=1;i<=n*2;i++) A[i]=A[i]-i;Tree::BD();printf("%d\n",La=Tree::F[1].f);
while(m--)scanf("%d%d",&x,&y),x^=La*p,y^=La*p,A[x]=y-x,Tree::Ins(x),A[x+n]=y-(x+n),Tree::Ins(x+n),printf("%d\n",La=Tree::F[1].f);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2021-06-06 CF1264D Beautiful Bracket Sequence
2021-06-06 AT3526 [ARC082C] ConvexScore