bzoj 5286: [Hnoi2018]轉盤


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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM