* ! AHOI/HNOI2018转盘
作者:互联网
线段树维护单调栈
又是一道非常棒的思维题!!!
SOL:
问题转化(倒着思考)
t时刻在某点,每次可以向后走一步或留在原地,然后t减1
每个点在\(T_i\)消失,求最小的\(t\)使得所有点都可以在消失前被访问
于是惊奇地发现留在原地一定不优,会一直往前走
破环为链(2倍),对于\(i\in[n,2n)\)走到j的时间为\(t-(i-j)\)
\(j\in(i-n]\)满足\(t-(i-j)>=T_j\to t_{min}=max(T_j-j)+i\)
\(ans=min_{i\in[n,2n)}(max_{j\in(i-n,i]}a_j+i),a_j=T_j-j\)
用i代替i+n-1
\(ans=min_{i\in[1,n])}(max_{j\in[i,2n]}a_j+i)+n-1\)因为\(a_i>a_{i+n}\)
若\(a_j\)为后缀最大值,i为j前第一个比\(a_j\)大的位置,\(ans=a_j+i+n\)
需要维护一个单调栈
线段树维护单调栈——楼房重建
每个区间记录最大值及单调栈长度,合并时左边肯定都是单调栈的内容,右边二分一个位置恰好大于左边分最大值则剩余的加入单调栈,时间复杂度\(O(nlog_n^2)\)
\(p_0,p_1,…,p_k\)是栈里留下的元素
\(p_{j-1}<n<=p_j\)
\(ans=min_{i\in[1,j]}(a_{p_i}+p_{i-1})+n\)
因为\((n,2n]\)里的最大值是\([1,n]\)里的最大值-n,所以只用维护\([1,n]\)
记\(mx[p]\)为区间最大值,\(t[p]\)为区间左半到中间的最小答案
\(ans=query(1,1,n,mx[1]-n)\)
时间复杂度\(O(nlog_n^2)\)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4,inf=1e9;
int n,m,op,ans,a[N],mx[N<<2],t[N<<2];
#define lc (p<<1)
#define rc (p<<1|1)
int query(int p,int l,int r,int x){
if(l==r)return mx[p]>x?x+l:inf;
int mid=l+r>>1;
return mx[rc]>x?min(t[p],query(rc,mid+1,r,x)):query(lc,l,mid,x);
}
inline void pushup(int p,int l,int r){
mx[p]=max(mx[lc],mx[rc]);
t[p]=query(lc,l,r,mx[rc]);
}
void build(int p,int l,int r){
if(l==r){
mx[p]=a[l]-l;
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p,l,mid);
}
void modify(int p,int l,int r,int x,int y){
if(l==r){
mx[p]=y-x;
return;
}
int mid=l+r>>1;
if(x<=mid)modify(lc,l,mid,x,y);
else modify(rc,mid+1,r,x,y);
pushup(p,l,mid);
}
int main(){
n=read();m=read();op=read();
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
ans=query(1,1,n,mx[1]-n)+n;
cout<<ans<<"\n";
while(m--){
static int x,y;
x=read();y=read();
if(op){x^=ans;y^=ans;}
modify(1,1,n,x,y);
ans=query(1,1,n,mx[1]-n)+n;
cout<<ans<<"\n";
}
return (0-0);
}
标签:AHOI,int,最大值,ans,mid,rc,HNOI2018,mx,转盘 来源: https://www.cnblogs.com/aurora2004/p/12604395.html