luogu P4425 [HNOI/AHOI2018]转盘
题面传送门
首先发现这个东西又可以走又可以不走很难受,所以考虑推一点性质。
我们不妨将整个过程倒过来,改成从终点向起点走。
容易发现我们至少要绕一圈,但是绕了一圈之后再走的路就没有意义了因为之后一定要再走一遍,所以可以看做在起点等了一段时间一直走到终点。
断环为链之后不难发现我们要求的东西长这个样子:\(\min\limits_{i=1}^{n}{i+n-1+\max\limits_{j=i}^{i+n-1}{A_j-j}}\)。
因为\(A_{i}=A_{i+n}\),所以\(A_{i}-i>A_{i+n}-(i+n)\),上面这个式子可以改写成一个后缀\(\max\)的形式:\(\min\limits_{i=1}^{n}{i+n-1+\max\limits_{j=i}^{2n}{A_j-j}}\)
发现这个形式很像楼房重建,那么就用线段树维护一个单调栈就好了,时间复杂度\(O(n\log ^2n)\)
什么,你不会线段树维护单调栈?
对于一个节点在update的时候,计算这个区间内的单调栈长度,右区间的答案是一定会在这个节点的答案中的,而左区间需要递归处理,观察左区间的右区间,如果左区间的右区间大于当前节点右区间最大值,那么左区间的左区间一定在答案中,如果小于,那么左区间的右区间一定不在答案中,所以每次只有单侧递归,时间复杂度\(O(n\log ^2n)\)
这题只要维护这个单调栈首尾是啥然后合并一下就好了,因为答案只能在后缀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);
}