题意:链接
方法: Treap+LIS
解析:
刚看到题还蒙了一会,无从下手啊- -!
后来寻思找找规律。
画画样例以及瞎编了两组数据之后发现点问题…
答案递增?
然后才反应过来- -,当我们从小到大插入的时候,插入后的情况是不影响插入前的。
所以这样的话我们可以把整个序列先弄出来?
之后求一个LIS,这时候对于每一个数来说,他都有个LIS值,当然这个可能不是他插入之后的最优解,因为之前的值可能比他插入之后还要大。
所以我们再需要扫一下数组,更新下答案即可。
至于第一部分找序列,用treap实现是很优越的。
第二部分呢?n^2的做法显然这里是过不了的,所以nlogn就好。
大复杂度O(nlogn)
代码:
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
using namespace std;
int size,n,root;
struct node
{
int l,r,rnd,siz,w,v;
}tr[N];
void pushup(int rt)
{
tr[rt].siz=tr[tr[rt].l].siz+tr[tr[rt].r].siz+1;
}
void lturn(int &rt)
{
int t=tr[rt].r;
tr[rt].r=tr[t].l;
tr[t].l=rt;
tr[t].siz=tr[rt].siz;
pushup(rt);
rt=t;
}
void rturn(int &rt)
{
int t=tr[rt].l;
tr[rt].l=tr[t].r;
tr[t].r=rt;
tr[t].siz=tr[rt].siz;
pushup(rt);
rt=t;
}
void insert(int &rt,int v)
{
if(!rt)
{
rt=++size;
tr[rt].l=tr[rt].r=0,tr[rt].siz=1;
tr[rt].v=size,tr[rt].rnd=rand();
return;
}
tr[rt].siz++;
if(v<=tr[tr[rt].l].siz+1)
{
insert(tr[rt].l,v);
if(tr[tr[rt].l].rnd<tr[rt].rnd)rturn(rt);
}else
{
insert(tr[rt].r,v-tr[tr[rt].l].siz-1);
if(tr[tr[rt].r].rnd<tr[rt].rnd)lturn(rt);
}
}
int tot;
int seq[N];
void getseq(int rt)
{
if(tr[rt].l!=0)
getseq(tr[rt].l);
seq[++tot]=tr[rt].v;
if(tr[rt].r!=0)
getseq(tr[rt].r);
}
int f[N],d[N],ans[N];
int print[N];
void getlis()
{
memset(d,0x3f,sizeof(d));
d[0]=0;
d[1]=seq[1],f[1]=1;
int mx=1;
for(int i=2;i<=n;i++)
{
if(seq[i]>d[mx])
{
f[i]=++mx;
d[mx]=min(d[mx],seq[i]);
}else
{
int l=0,r=mx,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(d[mid]<seq[i])ans=mid,l=mid+1;
else r=mid-1;
}
f[i]=ans+1;
d[ans+1]=min(d[ans+1],seq[i]);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);x++;
insert(root,x);
}
getseq(root);
getlis();
for(int i=1;i<=n;i++)print[seq[i]]=f[i];
for(int i=1;i<=n;i++)print[i]=max(print[i],print[i-1]);
for(int i=1;i<=n;i++)printf("%d\n",print[i]);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 09:04:15