P3769 [CH弱省胡策R2] TATT 题解

考虑按照 44 维依次作为关键字排序,那么就是求这个序列的最长不降子序列,其中每一维度都要不降。

显然的 fif_i 表示以 ii 结尾的最长上升子序列,排序后有 fi=(maxj[1,i)bjbicjcidjdifj)+1f_i= (\max \limits_{j \in [1,i) \land b_j \leq b_i \land c_j \leq c_i \land d_j \leq d_i} f_j) + 1

直接做是三次方的,注意到这是一个三维偏序,可以直接上 K-D Tree 维护,复杂度 O(n53)O(n^\frac{5}{3}),可以通过。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;

const int N = 5e4 + 5;

int n;
int f[N], ans;
struct Point
{
	int x[4];
}p[N], g[N];

class KD_Tree
{
public:
	int idx;
	struct Node
	{
		int lson, rson;
		int x[3];
		int minn[3], maxn[3], val, maxval;
	}tr[N];
	void pushup(int u)
	{
		tr[u].maxval = max({ tr[tr[u].lson].maxval, tr[tr[u].rson].maxval, tr[u].val });
		for (auto& i : { 0, 1, 2 })
		{
			tr[u].minn[i] = min({ tr[u].x[i], (tr[u].lson ? tr[tr[u].lson].minn[i] : (int)2e9), (tr[u].rson ? tr[tr[u].rson].minn[i] : (int)2e9) });
			tr[u].maxn[i] = max({ tr[u].x[i], (tr[u].lson ? tr[tr[u].lson].maxn[i] : (int)-2e9), (tr[u].rson ? tr[tr[u].rson].maxn[i] : (int)-2e9) });
		}
	}
	int build(int l, int r, int g)
	{
		int u = ++idx;
		int mid = l + r >> 1;
		nth_element(p + l, p + mid, p + r + 1, [&](const auto& x, const auto& y) {return x.x[g + 1] < y.x[g + 1]; });
		tr[u].x[0] = p[mid].x[1], tr[u].x[1] = p[mid].x[2], tr[u].x[2] = p[mid].x[3];
		tr[u].val = 0;
		if (l == r)
		{
			pushup(u);
			return u;
		}
		if (l < mid) tr[u].lson = build(l, mid - 1, (g == 2 ? 0 : g + 1));
		if (mid < r) tr[u].rson = build(mid + 1, r, (g == 2 ? 0 : g + 1));
		pushup(u);
		return u;
	}
	void update(int x, int y, int z, int u, int val)
	{
		if (!u) return;
		if (tr[u].minn[0] > x || tr[u].maxn[0] < x || tr[u].minn[1] > y || tr[u].maxn[1] < y || tr[u].minn[2] > z || tr[u].maxn[2] < z) return;
		if (tr[u].x[0] == x && tr[u].x[1] == y && tr[u].x[2] == z)
		{
			tr[u].val = max(tr[u].val, val);
			pushup(u);
			return;
		}
		update(x, y, z, tr[u].lson, val);
		update(x, y, z, tr[u].rson, val);
		pushup(u);
	}
	int query(int x, int y, int z, int u)
	{
		if (!u) return (int)-2e9;
		if (tr[u].maxn[0] <= x && tr[u].maxn[1] <= y && tr[u].maxn[2] <= z) return tr[u].maxval;
		if (tr[u].minn[0] > x || tr[u].minn[1] > y || tr[u].minn[2] > z) return (int)-2e9;
		int res = (int)-2e9;
		if (tr[u].x[0] <= x && tr[u].x[1] <= y && tr[u].x[2] <= z) res = tr[u].val;
		res = max({ res, query(x, y, z, tr[u].lson), query(x, y, z, tr[u].rson) });
		return res;
	}
}tr;

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> p[i].x[0] >> p[i].x[1] >> p[i].x[2] >> p[i].x[3];
	}
	sort(p + 1, p + n + 1, [&](const auto& x, const auto& y) {for (auto& i : { 0, 1, 2, 3 }) { if (x.x[i] ^ y.x[i]) { return x.x[i] < y.x[i]; } } return false; });
	for (int i = 1; i <= n; i++) g[i] = p[i];
	tr.build(1, n, 0);
	for (int i = 1; i <= n; i++)
	{
		int res = tr.query(g[i].x[1], g[i].x[2], g[i].x[3], 1);
		f[i] = max(res, 0) + 1;
		tr.update(g[i].x[1], g[i].x[2], g[i].x[3], 1, f[i]);
		ans = max(ans, f[i]);
	}
	cout << ans << "\n";
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示