HDU 3564 Another LIS

题意:
有一个起初是空的序列。我们开始在序列中添加从1到N的数字,每次我们只在特定位置向序列添加一个数字。现在,我们想知道每次添加后LIS(最长上升子序列)的长度。
题解:
一个神奇的LIS题,题解见附件

#pragma GCC optimize (4)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100000+10;
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
namespace GET{
    char ch;
    inline char read(){
        #define MAX 10000000
        static char buf[MAX],*s,*t;
        if(s==t){
            t=(s=buf)+fread(buf,1,MAX,stdin);
            if(s==t)return EOF;
        }
        return *s++;
    }
    // #define getchar read
    template <typename T>
    inline void Read(T &x){
        while(ch<'0'||ch>'9')ch=getchar();
        x=ch-'0';ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^'0');
            ch=getchar();
        }
    }
    inline void Write(int x){
        if(x>10)Write(x/10);
        putchar(x%10+'0');
    }
}
using namespace GET;
struct Tree{
        int left,right;
        int sum;
}a[maxn<<2];
int n,ans;
int A[maxn],Low[maxn],val[maxn];
void Init();
void LIS();
void Pushup(int);
void Build(int,int,int);
void Update(int,int,int);
signed main(){
        // freopen("in.cpp","r",stdin);
        Init();
        return 0;
}
void Init(){
        Read(n);
        Build(1,1,n);
        for(int i=1;i<=n;i++)Read(A[i]);
        for(int i=n;i>=1;i--)Update(1,i,A[i]+1);
        LIS();
}
void LIS(){
        Low[1]=val[1];ans=1;//val记录最终的序列
        printf("%d\n",ans );
        for(int i=2;i<=n;i++){//接下来的就是二分求LIS
                int x=lower_bound(Low+1,Low+1+ans,val[i])-Low;
                ans=max(x,ans);
                Low[x]=val[i];
                printf("%d\n",ans);
        }
}
void Pushup(int u){
        a[u].sum=a[u<<1].sum+a[u<<1|1].sum;
}
void Build(int u,int left,int right){
        a[u].left=left;a[u].right=right;
        if(left==right){
                a[u].sum=1;return;
        }
        int mid=(left+right)>>1;
        Build(u<<1,left,mid);
        Build(u<<1|1,mid+1,right);
        Pushup(u);
}
void Update(int u,int key,int p){
        if(a[u].left==a[u].right){
                val[key]=a[u].left;
                a[u].sum=0;
                return;
        }
        a[u].sum--;
        int mid=(a[u].left+a[u].right)>>1;
        if(a[u<<1].sum>=p)Update(u<<1,key,p);
        else Update(u<<1|1,key,p-a[u<<1].sum);
}

猜你喜欢

转载自www.cnblogs.com/holy-unicorn/p/9510360.html