bzoj3171 最长上升子序列 Treap&Lis

       首先用平衡树把最后的序列维护出来,然后统计每一位为结尾的LIS长度。然后维护一下答案就好了。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define N 200005
using namespace std;

int n,cnt,trtot,rt,bit[N],ans[N],a[N],c[N][2],sz[N],rd[N];
void maintain(int k){
	sz[k]=sz[c[k][0]]+sz[c[k][1]]+1;
}
void turn(int &k,int l){
	int t=c[k][l],r=l^1; c[k][l]=c[t][r]; c[t][r]=k;
	maintain(k); maintain(t); k=t;
}
void ins(int &k,int rst){
	if (!k){
		k=++trtot; sz[k]=1;
		rd[k]=rand(); return;
	}
	sz[k]++;
	if (rst>sz[c[k][0]]){
		ins(c[k][1],rst-sz[c[k][0]]-1);
		if (rd[c[k][1]]>rd[k]) turn(k,1);
	} else{
		ins(c[k][0],rst);
		if (rd[c[k][0]]>rd[k]) turn(k,0);
	}
}
void dfs(int x){
	if (!x) return;
	dfs(c[x][0]); a[++cnt]=x; dfs(c[x][1]);
}
void add(int x,int t){
	for (; x<=n; x+=x&-x) bit[x]=max(bit[x],t);
}
int getmax(int x){
	int t=0; for (; x; x-=x&-x) t=max(t,bit[x]); return t;
}
int main(){
	srand(26501); scanf("%d",&n); int i;
	for (i=1; i<=n; i++){
		int x; scanf("%d",&x); ins(rt,x);
	}
	dfs(rt); 
	for (i=1; i<=n; i++){
		ans[a[i]]=getmax(a[i]-1)+1;
		add(a[i],ans[a[i]]);
	}
	for (i=1; i<=n; i++) printf("%d\n",ans[i]=max(ans[i-1],ans[i]));
	return 0;
}


by lych

2016.2.23

你可能感兴趣的:(树状数组,最长上升子序列,treap,平衡树)