bzoj3173 & 洛谷P4309 [TJOI2013]最长上升子序列 LIS+FHQ Treap

题目链接:
洛谷4309
bzoj3173

题目要求动态插入点并求序列 L I S LIS LIS
首先LIS的递推公式:
d p [ i ] = m a x ( d p [ j ] ) + 1 , j &lt; i , a j &lt; a i dp[i]=max(dp[j])+1 , j&lt;i,a_j&lt;a_i dp[i]=max(dp[j])+1,j<i,aj<ai
发现这道题动态插入的点的权值是递增的。
因此 a j &lt; a i a_j&lt;a_i aj<ai的条件就不用管了。
问题转化为询问前面所有位置比当前位置小的dp值中的最大值+1。
怎么维护呢?动态插入节点,首先想到vector qwq
然而这是平衡树专题训练

czh:那你为什么不重复数字那一题用了map
zyd:因为我蒻qwq

所以建一棵非旋 T r e a p Treap Treap来维护之前的 d p dp dp值。
然后这里 s p l i t split split操作要改一下:
普通的 F H Q FHQ FHQ T r e a p Treap Treap的操作 s p l i t split split是按照权值分为两棵树。
但是这里不是对权值有要求,而是要求位置小于当前位置。
所以这里按照子树大小分成两棵树。
其他操作和普通非旋Treap一致qwq

代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
namespace I_Love {

const int Size=100005;
int n,tot,dp[Size];
#define lc(x) tree[x].ls
#define rc(x) tree[x].rs
struct node {
	int ls,rs;
	int pri;
	int val;
	int siz;
	int id;
} tree[Size];
inline void Pushup(int x) {
	tree[x].siz=tree[lc(x)].siz+tree[rc(x)].siz+1;
	tree[x].val=max(max(tree[lc(x)].val,tree[rc(x)].val),dp[tree[x].id]);
}
inline int New(int i,int v) {
	dp[i]=v;
	tree[++tot].val=v;
	tree[tot].siz=1;
	tree[tot].id=i;
	tree[tot].pri=rand();
	return tot;
}
int Merge(int x,int y) {
	if(!x || !y)	return x|y;
	if(tree[x].pri<tree[y].pri) {
		rc(x)=Merge(rc(x),y);
		Pushup(x);
		return x;
	} else {
		lc(y)=Merge(x,lc(y));
		Pushup(y);
		return y;
	}
}
void Split(int i,int k,int &x,int &y) {
	if(!i) {
		x=y=0;
	} else {
		if(tree[lc(i)].siz>=k) {
			y=i;
			Split(lc(i),k,x,lc(i));
		} else {
			x=i;
			Split(rc(i),k-tree[lc(i)].siz-1,rc(i),y);
		}
		Pushup(i);
	}
}
void Fujibayashi_Ryou() {
	n=read();
	int root=0;
	for(re i=1; i<=n; i++) {
		int a=0,b=0;
		Split(root,read(),a,b);
		//加入一个节点
		a=Merge(a,New(i,tree[a].val+1));
		//把分裂出来的两棵树合并回去
		root=Merge(a,b);
		printf("%d\n",tree[root].val);
	}
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
/*
9 3
2 4 3 6 1 5 8 9 7
3 5
2 6
1 4
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值