首页 > 其他分享 >洛谷 P8949 [YsOI2022] 淀粉树

洛谷 P8949 [YsOI2022] 淀粉树

时间:2024-04-10 16:44:06浏览次数:17  
标签:typedef leaf YsOI2022 int 洛谷 pb fa maxn P8949

洛谷传送门

考虑 \(d = 2\) 的部分分。相当于只用 \(2\) 次操作把 \(T\) 变成一条链。

不妨设最后变成的是一个 \(1 \sim n\) 的链,如果不是可以把点重编号。

第一次操作考虑以 \(n\) 为根,每次取每个儿子的子树中的最大值为新的根并和原来的根连边,这样会将整棵树具有堆的性质,即父亲的编号比儿子的编号大。

那么第二次操作时因为删完 \(1 \sim i - 1\) 的点后 \(i\) 一定是叶子,所以合法。

实现时发现第一次操作实际上是求点权 Kruskal 重构树,从小到大加点,并查集维护每个点所在子树的根即可。

\(d = 2\) 的部分分给我们启发。考虑若能让 \(S\) 逆操作 \(d - 2\) 次变成一条链,那么整道题就解决了。

考虑增量法,每次把 \(S\) 中的最大度数减 \(1\)。自底向上构造,若当前点的度数为最大度数,那么就断开它和父亲的连边,在子树里面随便找一个还没标记过的叶子,将父亲和这个叶子连边,并标记这个叶子。容易归纳证明每棵子树中未被标记的叶子个数 \(\ge 1\),所以不会出现所有叶子都被标记的情况。

时间复杂度 \(O(nd \log n)\)。

code
// Problem: P8949 [YsOI2022] 淀粉树
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8949
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

int n, m, p[maxn], q[maxn], tim, fa[maxn];
vector<int> G[maxn], ans[maxn], leaf[maxn];
set<int> S[maxn], T[maxn];

void dfs(int u, int fa, int d) {
	ans[d][u] = fa;
	bool fl = 1;
	for (int v : S[u]) {
		if (v == fa) {
			continue;
		}
		fl = 0;
		dfs(v, u, d);
		if (leaf[u].size() < leaf[v].size()) {
			swap(leaf[u], leaf[v]);
		}
		for (int x : leaf[v]) {
			leaf[u].pb(x);
		}
		vector<int>().swap(leaf[v]);
	}
	if (fl) {
		leaf[u].pb(u);
		return;
	}
	if ((int)T[u].size() == d) {
		assert((int)leaf[u].size() >= 2);
		int v = leaf[u].back();
		leaf[u].pop_back();
		T[fa].insert(v);
		T[v].insert(fa);
		T[fa].erase(u);
		T[u].erase(fa);
	}
}

void dfs2(int u, int fa, int d) {
	ans[d][u] = fa;
	p[u] = ++tim;
	q[tim] = u;
	for (int v : S[u]) {
		if (v == fa) {
			continue;
		}
		dfs2(v, u, d);
	}
}

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	if (n == 2) {
		puts("1\n0 1");
		return;
	}
	for (int i = 1; i <= m; ++i) {
		ans[i] = vector<int>(n + 2);
	}
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		S[u].insert(v);
		S[v].insert(u);
	}
	int rt = 0;
	for (int i = 1; i <= n; ++i) {
		if ((int)S[i].size() == 1) {
			rt = i;
			break;
		}
	}
	for (int d = m; d >= 3; --d) {
		for (int i = 1; i <= n; ++i) {
			vector<int>().swap(leaf[i]);
			T[i] = S[i];
		}
		dfs(rt, 0, d);
		for (int i = 1; i <= n; ++i) {
			S[i] = T[i];
		}
	}
	dfs2(rt, 0, 2);
	for (int i = 1; i <= n; ++i) {
		fa[i] = i;
	}
	for (int i = 1; i <= n; ++i) {
		for (int j : G[q[i]]) {
			j = find(j);
			if (p[j] < i) {
				ans[1][j] = q[i];
				fa[j] = q[i];
			}
		}
	}
	printf("%d\n", m);
	for (int i = 1; i <= m; ++i) {
		for (int j = 1; j <= n; ++j) {
			printf("%d%c", ans[i][j], " \n"[j == n]);
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,leaf,YsOI2022,int,洛谷,pb,fa,maxn,P8949
From: https://www.cnblogs.com/zltzlt-blog/p/18126344

相关文章

  • 洛谷题单指南-数学基础问题-P3383 【模板】线性筛素数
    原题链接:https://www.luogu.com.cn/problem/P3383题意解读:素数筛模版题。解题思路:素数筛介绍所谓素数(质数),是指除了1和它本身以外不再有其他因数的自然数,一般用试除法判断素数(时间复杂度:O(sqrt(n))):boolisprime(intx){if(x<=1)returnfalse;for(inti=2;i*......
  • 洛谷题单指南-数学基础问题-P2926 [USACO08DEC] Patting Heads S
    原题链接:https://www.luogu.com.cn/problem/P2926题意解读:有n个数,计算每个数能整除其他数的个数。解题思路:a[100005]记录所有的数,h[1000005]记录所有数的个数,cnt[1000005]记录所有数能整除其他数的个数只需要读入a数组,同时更新h[a[i]]++再依次从小到大遍历h的下标每一个数i,如......
  • 洛谷 P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two
    [USACO2.4]两只塔姆沃斯牛TheTamworthTwo题目描述两只牛逃跑到了森林里。FarmerJohn开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和John)。追击在的平面网格内进行。一个格子可以是:一个障碍物,两头牛(它们总在一起),或者FarmerJohn。两头牛和FarmerJohn......
  • 洛谷题单指南-数学基础问题-P2638 安全系统
    原题链接:https://www.luogu.com.cn/problem/P2638题意解读:把a个红球、b个黑球放入n个盒子,求所有的方法。解题思路:盒子中可以放也可以不放,可以放任意个,因此,题目可以转化为将i个红球(0<=i<=a),j个黑球(0<=j<=b)放入n个盒子的方案数之和,设f(n,i,j)表示将一个红球、j个黑球放入n......
  • 洛谷题单指南-数学基础问题-P3913 车的攻击
    原题链接:https://www.luogu.com.cn/problem/P3913题意解读:车所在的行、列一共有多个个格子。解题思路:假设3*3的棋盘,有三个车分析得知,三个车覆盖了第1、2两行,第2、3两列,覆盖的格子数用公式计算就是2*3+2*3-2*2=8也就是两行格子数加两列格子数再减去交叉点。因此......
  • 进阶版Python编程题(2)洛谷(小学数学N合一)
    问题1请输出 IloveLuogu!问题2这里有 10 个苹果,小A拿走了 2 个,Uim拿走了 4 个,小B拿走剩下的所有的苹果。我们想知道:小A和Uim两个人一共拿走多少苹果?小B能拿走多少苹果?现在需要编写一个程序,输出两个数字作为答案,中间使用空格分开。问题3现在有 1......
  • 进阶版Python编程题(1)洛谷
    题目描述学校和yyy的家之间的距离为 s千米,而yyy以 v 米每分钟的速度匀速走向学校。在上学的路上,yyy还要额外花费 10 分钟的时间进行垃圾分类。学校要求必须在上午 8:00 到达,请计算在不迟到的前提下,yyy最晚能什么时候出门。由于路途遥远,yyy可能不得不提前一......
  • 【题解】洛谷马的遍历
    马的遍历方法:广度优先搜索源代码如下#include<iostream>#include<queue>#include<cstdio>#include<cstring>usingnamespacestd;structcoord{//结构体定义x,y坐标intx,y;};queue<coord>Q;intans[500][500];//-1代表未访问intwalk[8......
  • 洛谷P1020导弹拦截
    ①题目描述某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截......
  • 洛谷题单指南-数学基础问题-P2789 直线交点数
    原题链接:https://www.luogu.com.cn/problem/P2789题意解读:n条直线可以形成不同交点数的方案数。解题思路:对于n=1、2、3、4的情况进行模拟:n=1时,有1种不同的交点数n=2时,有2种不同的交点数n=3时,有3种不同的交点数n=4时,有5种不同的交点数对n=4的情况,分情况讨......