Description
Solution
首先注意到一個點不會走兩次,只會有停下來等待的情況,把序列倍長
那么如果枚舉一個起點\(i\),答案就是 \(min(max(T[j]+n-(j-i)-1)),j∈[i,2*n]\)
相當於從 \(i\) 出發,先走到 \(j\) 停下來,然后再走完剩下的,如果不合法則不會更優
最優情況一定是把等待時間盡量用在前面(把起點往前移)
設 \(a[i]=T[i]-i\)
原式變為: \(min(max(a[j]+i)+n-1),j∈[i,2*n]\)
維護 \(max(a[j]+i)\) 即可,可以用線段樹維護,每一次修改向上合並維護這個東西
\(i,j\) 是有偏序關系的每一次要維護跨過 \(mid\) 的答案
向上合並需要一個 \(log\) 的遞歸查詢
復雜度是 \(O(n*log^2)\)
#include<bits/stdc++.h>
#define ls (o<<1)
#define rs (o<<1|1)
using namespace std;
const int N=2e5+10;
int n,tr[N*4],mx[N*4],Q,P,T[N],a[N],ans=0;
inline int qry(int l,int r,int o,int x){
if(l==r)return l+max(x,mx[o]);
int mid=(l+r)>>1;
if(mx[rs]>=x)return min(tr[o],qry(mid+1,r,rs,x));
return min(qry(l,mid,ls,x),mid+1+x);
}
inline void upd(int l,int r,int o){
int mid=(l+r)>>1;
tr[o]=qry(l,mid,ls,mx[rs]);
mx[o]=max(mx[ls],mx[rs]);
}
inline void build(int l,int r,int o){
if(l==r){tr[o]=T[l];mx[o]=a[l];return ;}
int mid=(l+r)>>1;
build(l,mid,ls);build(mid+1,r,rs);
upd(l,r,o);
}
inline void Modify(int l,int r,int o,int sa){
if(l==r){tr[o]=T[l];mx[o]=a[l];return ;}
int mid=(l+r)>>1;
if(sa<=mid)Modify(l,mid,ls,sa);
else Modify(mid+1,r,rs,sa);
upd(l,r,o);
}
int main(){
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
cin>>n>>Q>>P;
for(int i=1;i<=n;i++){
scanf("%d",&T[i]);T[i+n]=T[i];
a[i]=T[i]-i;a[i+n]=T[i+n]-i-n;
}
build(1,n*2,1);
printf("%d\n",ans=tr[1]+n-1);
int x,y;
while(Q--){
scanf("%d%d",&x,&y);x^=ans*P;y^=ans*P;
T[x]=y;T[x+n]=y;a[x]=T[x]-x;a[x+n]=T[x+n]-x-n;
Modify(1,n*2,1,x);Modify(1,n*2,1,x+n);
printf("%d\n",ans=tr[1]+n-1);
}
return 0;
}