【YBT2022寒假Day2 B】【luogu CF809D】模糊序列 / Hitchhiking in the Baltic States(平衡树优化DP)(fhq-Treap)

模糊序列 / Hitchhiking in the Baltic States

题目链接:YBT2022寒假Day2 B / luogu CF809D

题目大意

给你一个序列,然后每个位置有可以选的数的范围。
然后要你找到对于所有可能的序列它严格上升子序列的最大长度。

思路

很明显的 DP。
考虑列方程,发现数的范围很大,考虑从答案序列长度下手,设 \(f_{i,j}\) 为前 \(i\) 个数答案串为 \(j\) 长度的最后一个最小是多少。

那么我们显然可以得出这个东西是严格递增的。
那我们考虑新一个数放进来会怎么样。

前面比 \(l\) 小的一段全部都会可以放一个 \(l\),这个后面中比 \(r\) 小的一段全部都可以放比它大 \(1\) 的数。
然后前面那一段由于是递增只有最后一个会有效,所以我们可以相当于这样:
那这一段后面放一个 \(l\),然后把中间的一段全部加一,然后把中间后面的一个删掉。

不难想到可以用 fhq-Treap 加速实现。

代码

#include<cstdio>
#include<cstdlib>
#include<algorithm>

using namespace std;

int n, l, r;

struct fhq_Treap {
	int ls[1000001], rs[1000001], yj[1000001];
	int val[1000001], tot, sz[1000001], root;
	int lyza[1000001];
	
	int make_new(int va) {
		int now = ++tot;
		ls[now] = rs[now] = 0; yj[now] = rand();
		val[now] = va; sz[now] = 1; return now;
	}
	
	void up(int now) {
		sz[now] = sz[ls[now]] + sz[rs[now]] + 1;
	}
	
	void downa(int x, int va) {
		val[x] += va; lyza[x] += va;
	}
	
	void down(int now) {
		if (lyza[now]) {
			if (ls[now]) downa(ls[now], lyza[now]);
			if (rs[now]) downa(rs[now], lyza[now]);
			lyza[now] = 0;
		}
	}
	
	pair <int, int> split_rnk(int now, int rnk) {
		if (!now) return make_pair(0, 0);
		if (!rnk) return make_pair(0, now);
		pair <int, int> re;
		down(now);
		if (sz[ls[now]] >= rnk) {
			re = split_rnk(ls[now], rnk);
			ls[now] = re.second; up(now);
			re.second = now;
		}
		else {
			re = split_rnk(rs[now], rnk - sz[ls[now]] - 1);
			rs[now] = re.first; up(now);
			re.first = now;
		}
		return re;
	}
	
	pair <int, int> split_val(int now, int va) {
		if (!now) return make_pair(0, 0);
		pair <int, int> re;
		down(now);
		if (va < val[now]) {
			re = split_val(ls[now], va);
			ls[now] = re.second; up(now);
			re.second = now;
		}
		else {
			re = split_val(rs[now], va);
			rs[now] = re.first; up(now);
			re.first = now;
		}
		return re;
	}
	
	int merge(int x, int y) {
		if (!x || !y) return x + y;
		if (x) down(x); if (y) down(y);
		if (yj[x] < yj[y]) {
			rs[x] = merge(rs[x], y);
			up(x); return x;
		}
		else {
			ls[y] = merge(x, ls[y]);
			up(y); return y;
		}
	}
	
	void insert(int x, int rnk) {
		int now = make_new(x);
		pair <int, int> y = split_rnk(root, rnk);
		root = merge(merge(y.first, now), y.second);
	}
	
	void build(int l, int r) {
		for (int i = l; i <= r; i++)
			insert((i == 0) ? 0 : 2e9, i);
	}
	
	void work(int l, int r) {
		pair <int, int> x = split_val(root, l - 1);
		pair <int, int> y = split_val(x.second, r - 1);	
		downa(y.first, 1);
		
		pair <int, int> z = split_rnk(y.second, 1);
		y.second = z.second; int tmp = z.first;
		down(tmp); val[tmp] = l;
		root = merge(x.first, merge(tmp, merge(y.first, y.second)));
	}
}T;

int main() {
//	freopen("vague.in", "r", stdin);
//	freopen("vague.out", "w", stdout);
	
	srand(19491001);
	
	scanf("%d", &n);
	
	T.build(0, n);
	
	for (int i = 1; i <= n; i++) {
		scanf("%d %d", &l, &r);
		T.work(l, r);
	}
	
	printf("%d", T.sz[T.split_val(T.root, 2e9 - 1).first] - 1);
	
	return 0;
}
上一篇:vs安装体验


下一篇:[bzoj1070][SCOI2007]修车_费用流