Denso Create Programming Contest 2022(AtCoder Beginner Contest 239) E~F 题

E - Subtree K-th Max

  • 题意:给定一个以 1 为根的树,节点个数为 n(1e5),每个点都有自己的点权。需要回答 m(1e5) 次询问。每次询问给出两个数字 V,K,输出节点 V 的子树中第 K(20) 大的值。保证询问中的子树节点个数大于 K

  • 观察数据范围发现 K 最大为 20,所以 DFS 统计子树中前20大的值即可

    参考文章:浅谈 DFS 序

  • 拓展:如果没有 K20 的话就得考虑 DFS + 主席树来做了

PS: 子树问题可以用DFS转换成序列上的问题

AC Code

int n, q;
void solve() {
    cin >> n >> q;
    vector<vector<int>> X(n + 1, vector<int>(20));
    for (int i = 1; i <= n; i += 1) cin >> X[i][0];
    vector<vector<int>> G(n + 1);
    for (int i = 1, a, b; i < n; i += 1) {
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector<int> tmp(40);
    function<void(int, int)> DFS = [&](int u, int par) {
        for (int v : G[u]) if (v != par) {
                DFS(v, u);
                merge(X[u].begin(), X[u].end(), X[v].begin(), X[v].end(), tmp.begin(), greater<int>());
                for (int i = 0; i < 20; i += 1) X[u][i] = tmp[i];
            }
    };
    DFS(1, 0);
    for (int i = 0, V, K; i < q; i += 1) {
        cin >> V >> K;
        cout << X[V][K - 1] << "\n";
    }
}

F - Construct Highway

  • 题意:有 n(1e5)个点,你需要构造出一颗数,满足每个点的度数都为 d[i]d[i] 为题目给定的)。并目题目 已经给了 m(m<n1) 条边。

思路参考 (知乎—严格鸽

考虑一下贪心,我们先找到一个度数剩余为1的点 u ,再去找到一个度数剩余大于等于 2 的点 v ,满足两点之间是不联通的。那我们就连一条边给 (u,v).

但是怎么做呢?

我们可以按照题目给定的边来构造联通块,对于 (u,v) 我们保证两个点来自不同的连通块。

以下度数为剩余的度数

所以我们需要维护联通块总的度数,并将联通块分为度数等于 1,和度数大于等于 2 两种。前者为C1,后者为 C2 通过枚举 C2 中的联通块 vec ,将 vec 中的点与 C1 中的点连边,注意,最后 vec 中应该剩下一个点,而这个点就可以代表整个联通块 vec ,其度数为 1 ,我们将其加入到 C1 中。

可以得到,vecC1 中的点一定是不连通的。

这样的我们就可以构造出一颗树了,当然需要一些特判,具体我写到代码的注释里了。

int d[MAXN];
vector<int>g[MAXN];
int n, m, u, v;
void slove() {
	cin >> n >> m;
	int sum = 0;
	for (int i = 1; i <= n; i++) { cin >> d[i]; sum += d[i]; }
	if (sum != 2 * (n - 1))NO;//树的总度数为2*(n - 1)
	UF uf = UF(n);
	while (m--) {
		cin >> u >> v;
		d[u]--, d[v]--;
		uf.Union(u, v);
		if (d[u] < 0 || d[v] < 0)NO;//度数不能小于0
	}
	//处理联通块
	for (int u = 1; u <= n; u++) {
		while (d[u]--) {
			//这里我们这样可以方便的搞出联通块的最后一个点
			g[uf.findFather(u)].push_back(u);
		}
	}
	//度数为1     度数为2
	vector<int>c1; vector<vector<int>>c2;
	for (int u = 1; u <= n; u++) {
		if (g[u].size()) {
			if (g[u].size() == 1)c1.push_back(g[u][0]);
			else c2.push_back(g[u]);
		}
	}
	vector<pair<int, int>>ans;
	for (auto &vec : c2) {
		int last = vec.back(); vec.pop_back();//剩下一个点
		for (int u : vec) {
			if (c1.size() == 0)NO;//如果c1没有了
			int v = c1.back(); c1.pop_back();
			ans.push_back({ u,v });
			uf.Union(u, v);
		}
		c1.push_back(last);
	}
	//最后c1还是被push了,所以最后c1的个数一定要为2,如果个数大于2的话,不可能联通
	if (c1.size() != 2)NO;
	u = c1[0], v = c1[1];
	ans.push_back({ u,v });
	uf.Union(u, v);
	if (uf.count == 1)
		for (auto x : ans)cout << x.first << " " << x.second << endl;
	else NO;
}
posted @   RioTian  阅读(65)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)
点击右上角即可分享
微信分享提示

📖目录