Longest Increasing Subsequence HDU - 6284

/*
首先預處理好f g數組
 fi :以a[i]爲結尾的 最長上升子序列的長度
 gi :以a[i]爲開始的 最長上升子序列的長度
 mxx : 最長上升子序列的長度 
線段樹優化 nlogn
(不包含a[i]==0)

顯然把全部0換成x  只多是mxx變成mxx+1 

 而後咱們考慮一對 i j (下標)
 若 f[i]+g[j]==mxx 則 全部a[i]+1~~~a[j]-1之間的x 
 他們對用的lis長度爲mxx+1 
 而後枚舉i j涼了
 對於一個i 咱們只須要找到 他後面的 一個j 知足  f[i]+g[j]==mxx 而且a[j]最大
 而後維護bg[i] 表示長度爲g[j]==i的全部的 a[j]中最大的 
 從後往前枚舉i 而後維護 bg O(1)轉移 
 上述過程可能 i和bg維護的j之間 他沒有0 那就不能轉移
 因此 按0分段  遇到0 就把以前的信息更新bg 
 
 而後沒了 
  
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#define lc k*2
#define rc k*2+1
#define mid (l+r)/2
#define maxn 400010
#define ll long long
using namespace std;
ll n,a[maxn],f[maxn],s[maxn],g[maxn],as[maxn],bg[maxn],c[maxn][2];
void Insert(ll k,ll l,ll r,ll x,ll y){
    if(x==l&&r==x){
        s[k]=max(s[k],y);return;
    }
    if(x<=mid)Insert(lc,l,mid,x,y);
    else Insert(rc,mid+1,r,x,y);
    s[k]=max(s[lc],s[rc]);
}
ll Query(ll k,ll l,ll r,ll x,ll y){
    if(x>y)return 0;
    if(x<=l&&y>=r)return s[k];
    ll res=0;
    if(x<=mid)res=max(res,Query(lc,l,mid,x,y));
    if(y>mid)res=max(res,Query(rc,mid+1,r,x,y));
    return res;
}
int main(){
    while(~scanf("%lld",&n)){
        for(ll i=0;i<=n*4;i++)
            s[i]=f[i]=g[i]=as[i]=0;
        for(ll i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            //a[i]=rand();
            f[i]=1;g[i]=1;
        }
        ll mxx=1;
        for(ll i=1;i<=n;i++){
            if(a[i]==0)continue;
            ll mx=Query(1,1,n,1,a[i]-1);
            f[i]=mx+1;mxx=max(mxx,f[i]);
            Insert(1,1,n,a[i],f[i]);
        }
        for(ll i=0;i<=n*4;i++)s[i]=0;
        for(ll i=n;i>=1;i--){
            if(a[i]==0)continue;
            ll mx=Query(1,1,n,a[i]+1,n);
            g[i]=mx+1;Insert(1,1,n,a[i],g[i]);
        }
        for(ll i=0;i<=n*4;i++)bg[i]=0;
        ll cnt=0;a[0]=-1;
        for(ll i=n;i>=0;i--){
            if(a[i]==0){
                for(ll j=1;j<=cnt;j++)
                    bg[c[j][0]]=max(bg[c[j][0]],c[j][1]);
                cnt=0;bg[0]=n+1;
            }
            else{
                ll mx=bg[mxx-f[i]];
                c[++cnt][0]=g[i];c[cnt][1]=a[i];
                if(mx-1<a[i]+1)continue;
                as[a[i]+1]++;as[mx]--;
            }
        }
        ll ans=0;
        for(ll i=1;i<=n;i++)as[i]+=as[i-1];
        for(ll i=1;i<=n;i++){
            if(as[i]>0)ans+=i*(mxx+1);
            else ans+=i*mxx;
            //("%lld\n",ans);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索