BZOJ3173 [Tjoi2013]最長上升子序列(離線處理+Treap+LIS)

【題解】

離線處理:


第n個數的插入不會改變前n-1個數的相對位置,因此可以直接求得最終序列,第i次操作的答案就是僅含1~i的LIS 
最終序列可以用Treap求得;

由於僅含1~i的LIS = max( 僅含1~i-1的LIS , 以i爲結尾的LIS ),可以用O(N*logN)的動態規劃求出以每個數爲結尾的LIS,再遞推求出每步答案 


【代碼】

#include<stdio.h>
#include<stdlib.h>
int a[100005],ans[100005],g[100005];
int n,p=0,p2=0;
int max(int a,int b)
{
	if(a>b) return a;
	return b;
}
struct Node
{
	Node* ch[2];
	int v,r,s;
	int cmp_s(int x) const
	{
		if( x <= ch[0]->s + 1 ) return 0;
		return 1;
	}
};
Node *root,*null;
void init()
{
	null=new Node();
	null->ch[0] = null->ch[1] = NULL;
	null->v=null->r=null->s=0;
	root=null;
}
void gets(Node* &o)
{
	o->s = o->ch[0]->s + 1 + o->ch[1]->s;
}
void xz(Node* &o,int d)
{
	Node* k=o->ch[d^1];
	o->ch[d^1]=k->ch[d];
	k->ch[d]=o;
	gets(o);
	gets(k);
	o=k;
}
void tj(Node* &o,int x)
{
	if(o==null)
	{
		o=new Node();
		o->ch[0] = o->ch[1] = null;
		o->v=++p;
		o->r=rand();
		o->s=1;
		return;
	}
	int d=o->cmp_s(x);
	o->s++;
	if(d==1) x-= o->ch[0]->s + 1;
	tj(o->ch[d],x);
	if( o->ch[d]->r < o->r ) xz(o,d^1);
}
void geta(Node* &o)
{
	if(o->ch[0]!=null) geta(o->ch[0]);
	a[++p2]=o->v;
	if(o->ch[1]!=null) geta(o->ch[1]);
}
int find(int num,int left,int right)
{
	int mid;
	while(left<right)
	{
		mid=(left+right+1)/2;
		if(g[mid]>num) right=mid-1;
		else left=mid;
	}
	return left;
}
int main()
{
	srand(25);
	int i,x,len=0;
	init();
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&x);
		tj(root,x+1);
	}
	geta(root);
	for(i=1;i<=n;i++)
	{
		x=find(a[i],0,len)+1;
		ans[a[i]]=x;
		g[x]=a[i];
		len=max(len,x);
	}
	for(i=1;i<=n;i++)
	{
		ans[i]=max(ans[i-1],ans[i]);
		printf("%d\n",ans[i]);
	}
	return 0;
}


發佈了110 篇原創文章 · 獲贊 8 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章