首页 > 其他分享 >CF490F Treeland Tour

CF490F Treeland Tour

时间:2024-04-02 21:56:04浏览次数:20  
标签:p2 std p1 Treeland int rs Tour CF490F ans

CF490F Treeland Tour

线段树合并

考虑维护 \(lis_{u,i}/lds_{u,i}\) 当前子树 \(u\) 中以 \(i\) 结尾的上升子序列/下降子序列。考虑转移,实质上就是合并每个儿子的信息,用线段树合并即可。

考虑如何统计答案,当枚举到儿子 \(v\) 时,维护答案分两种情况:

选 \(u\) 点,那么就是前面的 \(ans=\max(ans, maxlis+vlds+1)\) 和 \(ans=\max(ans, maxlis+vlds+1)\)

不选 \(u\) 点,考虑在合并操作中统计答案。在合并时会枚举断点 \(mid\),此时 \(ans=\max(ans, lis_{p1_{ls}}+lds_{p2_{rs}})\) 或 \(ans=\max(ans, lis_{p2_{ls}}+lds_{p1_{rs}})\)。

这部分可能就我看得懂

复杂度 \(O(n\log n)\)。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

typedef long long i64;
const int N = 6010;
int n, cnt, num, ans;
int a[N];
int h[N];
struct node {
	int to, nxt; 
} e[N << 1];
void add(int u, int v) {
	e[++cnt].to = v;
	e[cnt].nxt = h[u];
	h[u] = cnt;
}
int ls[4000010], rs[1000010];
struct LS {
	int tot;
	int t[4000010];
	void pushup(int u, int ls, int rs) {t[u] = std::max(t[ls], t[rs]);}
	void ins(int &u, int l, int r, int x, int y) {
		if(!u) u = ++tot;
		if(l == r) {
			t[u] = std::max(t[u], y);
			return;
		}
		int mid = (l + r) >> 1;
		if(x <= mid) ins(ls[u], l, mid, x, y);
		else ins(rs[u], mid + 1, r, x, y);
		pushup(u, ls[u], rs[u]);
	}
	int query(int u, int l, int r, int L, int R) {
		if(R < L) return 0;
		if(L <= l && r <= R) {
			return t[u];
		}
		int mid = (l + r) >> 1, ret = 0;
		if(L <= mid) ret = std::max(ret, query(ls[u], l, mid, L, R));
		if(R > mid) ret = std::max(ret, query(rs[u], mid + 1, r, L, R));
		return ret;
	}
} lis, lds;
void mg(int p1, int p2, int l, int r) {
	if(l == r) {
		lis.t[p1] = std::max(lis.t[p1], lis.t[p2]);
		lds.t[p1] = std::max(lds.t[p1], lds.t[p2]);
		return;
	}
	int mid = (l + r) >> 1;
	int lv = ls[p1], rv = rs[p2];
	ans = std::max(ans, lis.t[lv] + lds.t[rv]);
	lv = ls[p2], rv = rs[p1];
	ans = std::max(ans, lis.t[lv] + lds.t[rv]);

 	if(ls[p1] && ls[p2]) mg(ls[p1], ls[p2], l, mid);
	else if(ls[p2]) ls[p1] = ls[p2];
	if(rs[p1] && rs[p2]) mg(rs[p1], rs[p2], mid + 1, r);
	else if(rs[p2]) rs[p1] = rs[p2];

	lis.pushup(p1, ls[p1], rs[p1]);
	lds.pushup(p1, ls[p1], rs[p1]);
}
void dfs(int u, int fa) {
	int mxlis = 0, mxlds = 0;
	for(int i = h[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == fa) continue;
		dfs(v, u);
		int vlis = lis.query(v, 1, num, 1, a[u] - 1), vlds = lds.query(v, 1, num, a[u] + 1, num);
		ans = std::max(ans, std::max(mxlis + vlds + 1, vlis + mxlds + 1));
		mxlis = std::max(mxlis, vlis);
		mxlds = std::max(mxlds, vlds);
		mg(u, v, 1, n);	
	}
	lis.ins(u, 1, num, a[u], mxlis + 1);
	lds.ins(u, 1, num, a[u], mxlds + 1);
}
int b[N];
void Solve() {
	std::cin >> n;

	lis.tot = lds.tot = n;
	for(int i = 1; i <= n; i++) {
		std::cin >> a[i];
		b[++num] = a[i];
	}
	std::sort(b + 1, b + n + 1);
	num = std::unique(b + 1, b + num + 1) - b - 1;
	for(int i = 1; i <= n; i++) {
		a[i] = std::lower_bound(b + 1, b + num + 1, a[i]) - b;
	}
	for(int i = 1; i < n; i++) {
		int u, v;
		std::cin >> u >> v;
		add(u, v), add(v, u);
	}

	dfs(1, 0);
	std::cout << ans << "\n";
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	Solve();

	return 0;
}

标签:p2,std,p1,Treeland,int,rs,Tour,CF490F,ans
From: https://www.cnblogs.com/FireRaku/p/18111585

相关文章

  • Kinetic Tournament Tree
    考虑这样一个问题:\(n\)个一次函数\(k_ix_i+b_i\),每个一次函数初始有\(x_i=0\);区间对\(x_i\)加正数\(x\),区间查询\(\max\limits_{i=l}^rk_ix_i+b_i\)。考虑每个点维护当\(x_i=0\)时值最大的函数,然后额外维护一个阈值\(t\),表示当\(x\)增大到\(t\)时这个......
  • AT_abc263_f [ABC263F] Tournament 题解
    分析一眼DP。定义状态函数$f_{i,j}$表示在第$i$此比赛中,获胜者为$j$时的最大奖学金。把比赛过程看成一棵倒着的满二叉树,就能发现:第$i$场比赛只会是其左儿子为根的子树中叶子节点的某一个与其右儿子为根的子树中叶子节点的某一个进行比赛。然后就可以得到转移方程:$f_{i,......
  • 旅游景点 Tourist Attractions (壮压 DP)题解
    简化题意题目链接——不卡内存班题目链接——卡内存版给定\(n\)个点和\(m\)条边组成的无向图,按照一定限制要求停留\(2\simk+1\)共\(k\)个点(可以经过但不停留),求最短的从\(1\)出发到\(n\)的路径长。限制情况如下:共有\(q\)个限制,接下来\(q\)行,每行两个数\(x......
  • P3577 [POI2014]TUR-Tourism 题解
    考虑在无向图上进行dfs,可以得到很多棵dfs树(因为图不一定连通),这些树形成了一个森林。然后由任意两点间不存在节点数超过\(10\)的简单路径这个限制可以得出这些树的深度都不超过\(10\),然后可以想到树上状压dp。有一个重要的性质,就是无向图dfs树上的非树边,一定是回边,所以......
  • AT_abc213_d [ABC213D] Takahashi Tour 题解(图&深搜)
    传送门题意有一个\(n\)个点的无向图。从根节点\(1\)开始,按如下规则遍历整个图:如果有连接这个点的其他点没有走过,则到这个点。如果有多个点,那么按从小到大的顺序走。如果有这个点没有其他点或者连接这个点的其他点都走过了,那么:如果这个点是根节点\(1\),结束。否则回......
  • Detours 的使用
    Detours是一个用于在ARM,ARM64,X86,X64和IA64机器上拦截二进制函数的库。Detours最常用来拦截应用程序中的win32api调用,比如添加调试工具。拦截代码在运行时动态应用。Detours将目标函数的前几个指令替换为无条件跳转到用户提供的detour函数它与 WriteProcess......
  • [ARC171E] Rookhopper's Tour 题解
    题目链接首先把\(m=2\)和\(m\)为奇数的情况判掉,由于我们要对合法的摆放方案计数,而一个摆放方案要判断合法性就必须通过一组合法的移动过程,对移动的状态进行记录以此转移和优化显然没啥前途,因此我们考虑摆放方案和移动过程之间的联系。一个比较显然的观察是摆放方案和移动过......
  • 题解 [ABC338D] Island Tour
    【洛谷博客】被降智的一道简单题。题意\(n\)个岛屿,第\(i\)座桥连接\(i\)和\(i+1\)(第\(N\)座桥连接着\(1\)和\(N\))。有一条长度为\(M\)的旅游序列\(X\),你需要按照顺序依次经过这些点,选择断掉一座桥使得旅游经过的桥最少。分析设断掉第\(i\)座桥会因为绕行增......
  • ABC338 D Island Tour 题解
    Question有\(n\)座海岛由\(n\)条桥连着,第\(i\)座桥连接第\(i\)和\(i+1\)座海岛,第\(n\)座桥连接第\(n\)和\(1\)座海盗有一条长度为\(m\)的旅游路线,第\(X_i\)表示依次到达的岛屿现在需要切断一条桥,求总旅游路线最小值Solution显然,从第\(X_{i-1}\)到\(X_......
  • CodeForces 814E An unavoidable detour for home
    洛谷传送门CF传送门考虑给图分层,一层的点一一对应上一层的一些点。设\(f_{i,j}\)为考虑了前\(i\)个点,最后一层有\(j\)个点,除了最后一层点的其他点度数限制已经满足的方案数。转移系数是\(g_{i,j,k}\)表示这一层有\(i\)个点,上一层有\(j\)个\(2\)度点,\(k\)个......