[CF1539F]Strange Array
Strange Array
题解
考虑我们如何求出一个数与这个序列中间数之间的距离。
 假设这个序列中有 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x个数比 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai大,有 
     
      
       
       
         y 
        
       
      
        y 
       
      
    y个数与 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai一样,有 
     
      
       
       
         z 
        
       
      
        z 
       
      
    z个数比 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai小。
 当 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai不小于这个序列的中间数时,它们之间的距离为 
     
      
       
       
         y 
        
       
         + 
        
       
         z 
        
       
         − 
        
        
        
          ⌈ 
         
         
          
          
            x 
           
          
            + 
           
          
            y 
           
          
            + 
           
          
            z 
           
          
         
           2 
          
         
        
          ⌉ 
         
        
       
         = 
        
        
        
          ⌊ 
         
         
          
          
            y 
           
          
            + 
           
          
            z 
           
          
            − 
           
          
            x 
           
          
         
           2 
          
         
        
          ⌋ 
         
        
       
      
        y+z-\left\lceil\frac{x+y+z}{2}\right\rceil=\left\lfloor\frac{y+z-x}{2}\right\rfloor 
       
      
    y+z−⌈2x+y+z⌉=⌊2y+z−x⌋。
 当 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai不大于这个序列的中间数时,它们之间的距离为 
     
      
       
       
         x 
        
       
         + 
        
       
         y 
        
       
         − 
        
        
        
          ⌊ 
         
         
          
          
            x 
           
          
            + 
           
          
            y 
           
          
            + 
           
          
            z 
           
          
         
           2 
          
         
        
          ⌋ 
         
        
       
         = 
        
        
        
          ⌈ 
         
         
          
          
            x 
           
          
            + 
           
          
            y 
           
          
            − 
           
          
            z 
           
          
         
           2 
          
         
        
          ⌉ 
         
        
       
      
        x+y-\left\lfloor\frac{x+y+z}{2}\right\rfloor=\left\lceil\frac{x+y-z}{2}\right\rceil 
       
      
    x+y−⌊2x+y+z⌋=⌈2x+y−z⌉。
 我们可以分大于中间数与小于中间数两种情况去求答案。
对于 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai不小于中间数的答案,我们先将所有数都赋值为 
     
      
       
       
         − 
        
       
         1 
        
       
      
        -1 
       
      
    −1,再从 
     
      
       
       
         i 
        
       
         = 
        
       
         1 
        
       
      
        i=1 
       
      
    i=1开始,将等于 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i的数的值赋值为 
     
      
       
       
         1 
        
       
      
        1 
       
      
    1。
 那么对于 
     
      
       
        
        
          a 
         
        
          j 
         
        
       
         = 
        
       
         i 
        
       
      
        a_{j}=i 
       
      
    aj=i,它的 
     
      
       
       
         y 
        
       
         + 
        
       
         z 
        
       
         − 
        
       
         x 
        
       
      
        y+z-x 
       
      
    y+z−x相当于是最大的一段区间和。
 我们求最大的区间和可以利用线段树来维护每个位置的前缀,记点 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i的前缀为 
     
      
       
       
         p 
        
       
         r 
        
        
        
          e 
         
        
          i 
         
        
       
      
        pre_{i} 
       
      
    prei,有
  
      
       
        
        
          ( 
         
        
          y 
         
        
          + 
         
        
          z 
         
        
          − 
         
        
          x 
         
         
         
           ) 
          
          
          
            m 
           
          
            a 
           
          
            x 
           
          
         
        
          = 
         
         
          
          
            max 
           
          
             
           
          
          
          
            k 
           
          
            = 
           
          
            j 
           
          
         
           n 
          
         
        
          p 
         
        
          r 
         
         
         
           e 
          
         
           k 
          
         
        
          − 
         
         
          
          
            min 
           
          
             
           
          
          
          
            k 
           
          
            = 
           
          
            0 
           
          
          
          
            j 
           
          
            − 
           
          
            1 
           
          
         
        
          p 
         
        
          r 
         
         
         
           e 
          
         
           k 
          
         
        
       
         (y+z-x)_{max}=\max_{k=j}^{n}pre_{k}-\min_{k=0}^{j-1}pre_{k} 
        
       
     (y+z−x)max=k=jmaxnprek−k=0minj−1prek
 我们可以通过线段树的区间修改来维护前缀,通过线段树的区间最值来求出它的最大/小前缀。
 对于 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai不大于中间数的答案,做法是相同的,只需要从 
     
      
       
       
         i 
        
       
         = 
        
       
         n 
        
       
      
        i=n 
       
      
    i=n开始即可。
时间复杂度 O ( n l o g n ) O\left(nlog\,n\right) O(nlogn)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int iv2=5e8+4;
const int lim=1000000;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,a[MAXN],ans[MAXN];
vector<int>vec[MAXN];
class SegmentTree{
	public:
		int trmx[MAXN<<2],trmn[MAXN<<2],lzy[MAXN<<2];
		void pushup(int rt){
			trmx[rt]=max(trmx[rt<<1],trmx[rt<<1|1]);
			trmn[rt]=min(trmn[rt<<1],trmn[rt<<1|1]);
		}
		void pushdown(int rt,int l,int r){
			if(lzy[rt]){
				int mid=l+r>>1;
				trmx[rt<<1]+=lzy[rt];trmx[rt<<1|1]+=lzy[rt];
				trmn[rt<<1]+=lzy[rt];trmn[rt<<1|1]+=lzy[rt];
				lzy[rt<<1]+=lzy[rt];lzy[rt<<1|1]+=lzy[rt];
				lzy[rt]=0;
			}
		}
		void build(int rt,int l,int r,int aw){
			lzy[rt]=0;if(l==r){trmx[rt]=trmn[rt]=l*aw;return ;}int mid=l+r>>1;
			build(rt<<1,l,mid,aw);build(rt<<1|1,mid+1,r,aw);pushup(rt);
		}
		void modify(int rt,int l,int r,int al,int ar,int aw){
			if(l>r||l>ar||r<al||al>ar)return ;
			if(al<=l&&r<=ar){trmx[rt]+=aw;trmn[rt]+=aw;lzy[rt]+=aw;return ;}
			int mid=l+r>>1;pushdown(rt,l,r);
			if(al<=mid)modify(rt<<1,l,mid,al,ar,aw);
			if(ar>mid)modify(rt<<1|1,mid+1,r,al,ar,aw);
			pushup(rt);
		}
		int queryMax(int rt,int l,int r,int al,int ar){
			if(l>r||l>ar||r<al||al>ar)return -INF;int mid=l+r>>1,res=-INF;
			if(al<=l&&r<=ar)return trmx[rt];pushdown(rt,l,r);
			if(al<=mid)res=max(res,queryMax(rt<<1,l,mid,al,ar));
			if(ar>mid)res=max(res,queryMax(rt<<1|1,mid+1,r,al,ar));
			return res; 
		}
		int queryMin(int rt,int l,int r,int al,int ar){
			if(l>r||l>ar||r<al||al>ar)return INF;int mid=l+r>>1,res=INF;
			if(al<=l&&r<=ar)return trmn[rt];pushdown(rt,l,r);
			if(al<=mid)res=min(res,queryMin(rt<<1,l,mid,al,ar));
			if(ar>mid)res=min(res,queryMin(rt<<1|1,mid+1,r,al,ar));
			return res; 
		}
}T;
signed main(){
	read(n);
	for(int i=1;i<=n;i++)read(a[i]),vec[a[i]].push_back(i);
	T.build(1,0,n,-1);
	for(int i=n;i>0;i--){
		int siz=vec[i].size();
		for(int j=0;j<siz;j++)T.modify(1,0,n,vec[i][j],n,2);
		for(int j=0;j<siz;j++){
			int tmp=T.queryMax(1,0,n,vec[i][j],n)-T.queryMin(1,0,n,0,vec[i][j]-1);
			ans[vec[i][j]]=max(ans[vec[i][j]],tmp/2);
		}
	} 
	T.build(1,0,n,-1);
	for(int i=1;i<=n;i++){
		int siz=vec[i].size();
		for(int j=0;j<siz;j++)T.modify(1,0,n,vec[i][j],n,2);
		for(int j=0;j<siz;j++){
			int tmp=T.queryMax(1,0,n,vec[i][j],n)-T.queryMin(1,0,n,0,vec[i][j]-1)-1;
			ans[vec[i][j]]=max(ans[vec[i][j]],tmp/2);
		}
	} 
	for(int i=1;i<=n;i++)printf("%d ",ans[i]);puts("");
	return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号