其他分享
首页 > 其他分享> > "蔚来杯"2022牛客暑期多校训练营3

"蔚来杯"2022牛客暑期多校训练营3

作者:互联网

比赛链接:

https://ac.nowcoder.com/acm/contest/33188

A.Ancestor

题意:

已知两棵有 \(n\) 个节点的树 \(A\) 和 \(B\),每个节点都有自己对应的权重,有一个长为 \(k\) 的序列 \(x\),表示树中的关键节点,第 \(i\) 轮删除 \(x_i\) 这个关键节点,问 \(A\) 树中剩余关键节点的最近公共祖先的权重是否大于 \(B\) 树种剩余关键节点的最近公共祖先的权重。

思路:

删除了第 \(i\) 个节点,剩余节点的 \(lca\) 其实就是 \(lca(lca(a_1, a_2, ..., a_{i - 1}), lca(a_{i + 1}, ..., a_n))\)。所以先处理所有关键节点的一个前缀的 \(lca\),和一个后缀的 \(lca\),然后比较权重即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
struct Tree{
	vector <int> top, son, dep, parent, sz;
	vector < vector<int> > e;
	Tree(int n) : top(n + 1), son(n + 1), dep(n + 1), parent(n + 1), sz(n + 1), e(n + 1) {}
	void add(int u, int v){
		e[u].push_back(v);
		e[v].push_back(u);
	}
	void init(int s){
		dfs1(s);
		dfs2(s, s);
	}
	void dfs1(int u){  //计算子树大小、深度、父亲和重儿子
		sz[u] = 1;
		dep[u] = dep[parent[u]] + 1;
		for (auto v : e[u]){
			if (v == parent[u]) continue;
			parent[v] = u;
			dfs1(v);
			sz[u] += sz[v];
			if (!son[u] || sz[son[u]] < sz[v]){
				son[u] = v;
			}
		}
	}
	void dfs2(int u, int up){  //计算链的头部节点
		top[u] = up;
		if (son[u]) dfs2(son[u], up);
		for (auto v : e[u]){
			if (v == parent[u] || v == son[u]) continue;
			dfs2(v, v);
		}
	}
	int lca(int u, int v){
		while(top[u] != top[v]){
			if (dep[top[u]] >= dep[top[v]]){
				u = parent[top[u]];
			}
			else{
				v = parent[top[v]];
			}
		}
		return (dep[u] < dep[v] ? u : v);
	}
};
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL n, k;
	cin >> n >> k;
	vector <LL> x(k), a(n + 1), b(n + 1);
	for (int i = 0; i < k; i ++ )
		cin >> x[i];
	Tree A(n), B(n);
	for (int i = 1; i <= n; i ++ )
		cin >> a[i];
	for (int u = 2; u <= n; u ++ ){
		LL v;
		cin >> v;
		A.add(u, v);
	}
	for (int i = 1; i <= n; i ++ )
		cin >> b[i];
	for (int u = 2; u <= n; u ++ ){
		LL v;
		cin >> v;
		B.add(u, v);
	}
	A.init(1);
	B.init(1);
	vector <LL> preA(k), preB(k);
	for (int i = 0; i < k; i ++ ){  //处理前缀
		if (!i){
			preA[i] = x[i];
			preB[i] = x[i];
		}
		else{
			preA[i] = A.lca(preA[i - 1], x[i]);
			preB[i] = B.lca(preB[i - 1], x[i]);
		}
	}
	vector <LL> sufA(k), sufB(k);
	for (int i = k - 1; i >= 0; i -- ){  //处理后缀
		if (i == k - 1){
			sufA[i] = x[i];
			sufB[i] = x[i];
		}
		else{
			sufA[i] = A.lca(sufA[i + 1], x[i]);
			sufB[i] = B.lca(sufB[i + 1], x[i]);
		}
	}
	LL ans = 0;
	for (int i = 0; i < k; i ++ ){
		if (!i){
			if (a[sufA[1]] > b[sufB[1]]){
				ans ++ ;
			}
		}
		else if (i == k - 1){
			if (a[preA[k - 2]] > b[preB[k - 2]]){
				ans ++ ;
			}
		}
		else{
			if (a[A.lca(preA[i - 1], sufA[i + 1])] > b[B.lca(preB[i - 1], sufB[i + 1])]){
				ans ++ ;
			}
		}
	}
	cout << ans << "\n";
	return 0;
}

C.Concatenation

题意:

给定 \(s\) 个字符串,输出将它们拼接起来后字典序最小的字符串。

思路:

直接 \(sort\),stable_sort 较稳定。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL n;
	cin >> n;
	vector <string> s(n);
	for (int i = 0; i < n; i ++ )
		cin >> s[i];
	sort(s.begin(), s.end(), [](string a, string b){
		return a + b < b + a;
	});
	for (int i = 0; i < n; i ++ )
		cout << s[i];
	return 0;
}

标签:parent,int,蔚来,top,多校,son,牛客,lca,++
来源: https://www.cnblogs.com/Hamine/p/16531498.html