ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-07-30 20:36:12  阅读:167  来源: 互联网

标签:parent int 蔚来 top 多校 son 牛客 lca ++


比赛链接:

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有