2021.12.07 [TJOI2013]最长上升子序列(Treap+DP)

https://www.luogu.com.cn/problem/P4309

题意:

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

分析:

对于第 \(i\) 个插进去的数字 \(i\) ,插到了第 \(x\) 位,则对于前 \(i\) 个数字的最长上升子序列 \(f[i]\)

\[f[i]=\max(f[1]+1,f[2]+1,f[3]+1,\cdots,f[i-1]+1)\\ =\max(f[1],f[2],f[3],\cdots,f[i-1])+1 \]

所以只需要最后求一边最长上升子序列就行。

这里可以使用树状数组或者硬算。

插入那就按照子树大小分割,一步步插入就行。

注:如果想使用 \(M\times v_1+v_2\) 这个方法插入,这是不行滴~比如:我现在第一位插入,又在第一位插入,在第二位插入,在第一位插入。按照这个方法插入结果是 4 2 1 3 ,而真正结果是 4 2 3 1

代码如下:

0pts:

Treap+树状数组

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=1e5+10;
int n,cnt,root,son[N][2],sizei[N],same[N],val[N],key[N],trueval[N];
int t[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void update(int x){
	sizei[x]=sizei[son[x][0]]+sizei[son[x][1]]+same[x];
}
inline void rotate(int &x,int flag){
	int y=son[x][flag^1];
	int change=son[y][flag];
	son[x][flag^1]=change;
	son[y][flag]=x;
	update(x);
	update(y);
	x=y;
}
inline void insert(int &x,int vali,int truevali){
	if(!x){
		x=++cnt;
		sizei[x]=same[x]=1;
		val[x]=vali;
		trueval[x]=truevali;
		key[x]=rand();
		return ;
	}
	if(val[x]==vali)return (void)(++sizei[x],++same[x]);
	int flag=vali>val[x];
	insert(son[x][flag],vali,truevali);
	if(key[x]<key[son[x][flag]])rotate(x,flag^1);
	update(x);
}
inline int rank_score(int x,int k){
	if(!x)return 0;
	if(sizei[son[x][0]]>=k)return rank_score(son[x][0],k);
	else if(sizei[son[x][0]]+same[x]>=k)return trueval[x];
	else return rank_score(son[x][1],k-sizei[son[x][0]]-same[x]);
}
inline int lowbit(int x){
	return x&-x;
}
inline void add(int x,int k){
	for(int i=x;i<=n;i+=lowbit(i))t[i]=max(t[i],k);
}
inline int query(int x){
	int fin=0;
	for(int i=x;i>0;i-=lowbit(i))fin=max(fin,t[i]);
	return fin;
}

signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		int x=read();
		x=x*(N-10)-i;
		insert(root,x,i);
	}
	for(int i=1;i<=n;i++){
		int x=rank_score(root,i);
		int y=query(x-1)+1;
		//cout<<x<<" "<<y<<endl;
		cout<<y<<endl;
		add(x,y);
	}
	return 0;
}

100pts:

Treap+硬算

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=1e5+10;
int n,cnt,root,son[N][2],sizei[N],same[N],val[N],key[N],trueval[N];
int t[N],a[N],ans[N],b[N],f[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void update(int x){
	sizei[x]=sizei[son[x][0]]+sizei[son[x][1]]+same[x];
}
inline void rotate(int &x,int flag){
	int y=son[x][flag^1];
	int change=son[y][flag];
	son[x][flag^1]=change;
	son[y][flag]=x;
	update(x);
	update(y);
	x=y;
}
inline void insert(int &x,int vali,int truevali){
	if(!x){
		x=++cnt;
		sizei[x]=same[x]=1;
		val[x]=vali;
		trueval[x]=truevali;
		key[x]=rand();
		return ;
	}
	int flag=0;
	if(vali<=sizei[son[x][0]])insert(son[x][0],vali,truevali),flag=0;
	else insert(son[x][1],vali-sizei[son[x][0]]-same[x],truevali),flag=1;
	if(key[x]<key[son[x][flag]])rotate(x,flag^1);
	update(x);
}
inline void work(int x){
	if(son[x][0])work(son[x][0]);
	a[++n]=trueval[x];
	if(son[x][1])work(son[x][1]);
}

signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		int x=read();
		//x=x*(N-10)-i;
		insert(root,x,i);
	}
	n=0;
	work(root);
	for(int i=1;i<=n;i++)b[i]=n+1;
	//for(int i=1;i<=n;i++)cout<<a[i]<<" ";cout<<endl;//
	for(int i=1;i<=n;i++){
		int x=lower_bound(b,b+n+1,a[i])-b;
		f[i]=x;
		b[f[i]]=min(b[f[i]],a[i]);
		ans[a[i]]=f[i];
		//cout<<x<<" "<<ans[a[i]]<<endl;//
	}
	for(int i=1;i<=n;i++)ans[i]=max(ans[i],ans[i-1]);
	for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
	return 0;
}
 posted on 2021-12-07 21:40  eleveni  阅读(36)  评论(0)    收藏  举报