单调栈+线段树——cf1220F

 首先考虑初始排列,pi会让周围所有比其大的元素深度+1,所以要求每个点的深度,只要其被覆盖了几次即可

这个覆盖可以通过处理每个元素的左右边界(单调栈O(n))+线段树区间更新(Ologn(n))来做

然后是将排列最左边一个元素移到最右边:

  在左边删元素pi,只会让pi右边所有比其大的元素深度-1,

  在右边加上元素pi,会让pi左边比其大的元素深度+1

这种循环左右移动,需要频繁更改线段树的下标,不好操作,所以我们一开始直接用一个两倍的数组来建立线段树,只要查询时查询长度为n即可

#include
#include
using namespace std;
#define N 400005

int n,a[N],L[N],R[N];

void work(){
    stack<int>stk;    
    a[2*n+1]=0;
    for(int i=1;i<=2*n+1;i++){
        if(stk.empty()){stk.push(i);continue;}
        while(stk.size() && a[stk.top()]>=a[i]){
            R[stk.top()]=i-1;
            stk.pop();
        }
        stk.push(i);
    }
    
    while(stk.size())stk.pop();
    a[0]=0;
    for(int i=2*n;i>=0;i--){
        if(stk.empty()){stk.push(i);continue;}
        while(stk.size() && a[stk.top()]>=a[i]){
            L[stk.top()]=i+1;
            stk.pop();
        }
        stk.push(i);
    }
}

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int lazy[N<<2],Max[N<<2];
void pushdown(int rt){
    if(lazy[rt]){
        lazy[rt<<1]+=lazy[rt];Max[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];Max[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
void update(int L,int R,int v,int l,int r,int rt){
    if(L<=l && R>=r){Max[rt]+=v;lazy[rt]+=v;return;}
    int m=l+r>>1;
    pushdown(rt);
    if(L<=m)update(L,R,v,lson);
    if(R>m)update(L,R,v,rson);
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l && R>=r)return Max[rt];
    int m=l+r>>1,res=0;
    pushdown(rt);
    if(L<=m)res=max(res,query(L,R,lson));
    if(R>m)res=max(res,query(L,R,rson));
    return res;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)a[i+n]=a[i];

    work();//处理出每个元素可以控制的范围 
    
    for(int i=1;i<=n;i++)
        update(L[i],R[i],1,1,2*n,1);
    
    int ans=query(1,n,1,2*n,1),pos=0;
    for(int i=1;i){
        int s=i,t=i+n;
        update(L[s],R[s],-1,1,2*n,1);//把s从左端删掉 
        update(L[t],R[t],1,1,2*n,1);//把t加入右端 
        int res=query(s+1,t,1,2*n,1);
        if(res<ans){
            ans=res,pos=i;
        } 
    }
    
    cout<" "<'\n';
    return 0;
}

 

你可能感兴趣的:(单调栈+线段树——cf1220F)