首页 > 其他分享 >Tree Compass Codeforces Round 934 (Div. 2) 1944E

Tree Compass Codeforces Round 934 (Div. 2) 1944E

时间:2024-03-21 11:59:17浏览次数:18  
标签:rt int Tree Codeforces Compass 操作 直径 d2 d1

Problem - E - Codeforces

题目大意:有一棵n个点的树,初始状态下所有点都是白色的,每次操作可以选择一个点u和一个距离dis,使得距离点u所有长度为dis的点变为黑色,问最少需要多少次操作能使所有点变成黑色,输出所有操作

1<=n<=2000

思路:要想操作数最少,就要使每次操作涂黑的点的数量尽可能多,那么也就是要找这棵树的中心点,而这样的点一定在树的直径上,也就是树上的最长链,直径可以通过两次bfs找最远点或者一次树上dp来找,这里只讲树上dp做法。

经过某个点u的最长链长度应为它的最长子链长度+次长子链长度,所以后序dfs求每个点距离叶子节点的距离的d1[u]维护最长子链的长度,d2[u]维护次长子链的长度,这样直径就等于d1[u]+d2[u]的最大值,记录取得最大值的点为根rt。

知道了直径以后还需要知道直径上的中点,所以在上述过程中用child维护每个点在最长子链中的子节点,这样从rt节点就可以向下找到中点。

如果直径的长度是偶数,也就是直径上有奇数个点,那么中点只有唯一一个,只需要在那个点处操作0到d/2的所有距离即可。

如果直径的长度是奇数,这时中点会有两个,那么如果只用其中一个点操作,操作次数将会是(d+1)/2+1,如果我们分别用两个点交叉操作,可能会出现下面这样的情况:

我们操作4 1 、4 3、5 1、5 3,只需要4次,如果只操作一个中点就需要5次,少一次的原因是我们每次操作都涂黑了至少2个点,只操作一个中点 的话必然会有只涂黑一个点的操作,而要想每次操作都涂黑至少两个点也需要直径的点数是4的倍数,这样才能两个中点交叉操作,所以只需要分两类讨论即可。

//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
typedef long long ll;
const ll MOD = 1e9 + 7;
ll n;
vector<int>g[N];
int d1[N],d2[N];
int child[N];
int d;
int rt;
void init()
{
	for (int i = 0; i <= n; i++)
	{
		g[i].clear();
		d1[i] = 0;
		d2[i] = 0;
		child[i] = 0;
		d = 0;
		rt = 1;
	}
}
void dfs(int u, int fa)
{
	for (int i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i];
		if (v == fa)
		{
			continue;
		}
		dfs(v, u);
		int temp = d1[v] + 1;//当前点到最远的叶子结点的距离
		if (temp > d1[u])
		{
			d2[u] = d1[u];//维护次长子链
			d1[u] = temp;//维护最长子链
			child[u] = v;//维护最长子链上的子节点关系
		}
		else if (temp > d2[u])
		{
			d2[u] = temp;
		}
	}
	if (d1[u] + d2[u] > d)
	{//当前点在直径上
		d = d1[u] + d2[u];
		rt = u;
	}
	
}
void solve()
{
	cin >> n;
	init();
	if (n == 1)
	{
		cout << 1 << '\n' << 1 << " " << 0 << '\n';
		return;
	}
	for (int i = 1; i < n; i++)
	{
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, 0);
	int dif = d / 2 - d2[rt];//最长链和次长链的差
	while (dif)
	{
		rt = child[rt];//找到中心点
		dif--;
	}
	if (d % 2 == 0 || d1[rt] % 2 == 1)
	{//直径长度是偶数或者最长子链长度是奇数(这时候点数一定不是4的倍数),只用一个中点就行
		cout << (d - 1) / 2 + 1 + 1 << '\n';
		for (int i = 0; i <= d1[rt]; i++)
		{
			cout << rt << " " << i << '\n';
		}
	}
	else
	{//分别用两个中点交叉操作
		cout << d / 2 + 1 << '\n';
		int temp = d - d1[rt];
		int temp2 = temp;
		while (temp2>=0)
		{
			cout << rt << " " << temp2 << '\n';
			temp2 -= 2;
		}
		temp2 = temp;
		rt = child[rt];
		while (temp2>=0)
		{
			cout << rt << " " << temp2 << '\n';
			temp2 -= 2;
		}
	}
	//cout << '\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

标签:rt,int,Tree,Codeforces,Compass,操作,直径,d2,d1
From: https://blog.csdn.net/ashbringer233/article/details/136823849

相关文章

  • LeetCode 2265. Count Nodes Equal to Average of Subtree
    原题链接在这里:https://leetcode.com/problems/count-nodes-equal-to-average-of-subtree/description/题目:Giventhe root ofabinarytree,return thenumberofnodeswherethevalueofthenodeisequaltothe average ofthevaluesinits subtree.Note:Th......
  • 集合系列(五) -TreeMap详解
    一、摘要在集合系列的第一章,咱们了解到,Map的实现类有HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等等。本文主要从数据结构和算法层面,探讨TreeMap的实现。二、简介JavaTreeMap实现了SortedMap接口,也就是说会按照key的大......
  • Codeforces Round 935 (Div. 3) A-G
    A传送门  先考虑无解情况,外在人的数量如果%3之后还剩下x人,只能靠第三类综合性人y来补充进去,如果x+y小于3则无解,有解只需要向上取整即可。#include<bits/stdc++.h>usingll=longlong;typedefstd::pair<int,int>PII;typedefstd::array<int,4>ay;constintN=......
  • LeetCode 1161. Maximum Level Sum of a Binary Tree
    原题链接在这里:https://leetcode.com/problems/maximum-level-sum-of-a-binary-tree/description/题目:Giventhe root ofabinarytree,thelevelofitsrootis 1,thelevelofitschildrenis 2,andsoon.Returnthe smallest level x suchthatthesumofa......
  • CodeForces 1945H GCD is Greater
    洛谷传送门CF传送门感觉是这场唯一比较有趣的题?首先明确一点:先手只会选\(2\)个数,因为数多了\(\gcd\)会变小,而且对方的\(\text{and}\)会变大。所以对于某一位,若\(0\)的个数\(\ge3\)那么对方的按位与这一位一定是\(0\)。所以若\(0\)的个数\(\le2\),那么可能会......
  • Codeforces Round 923 (Div. 3) D. Find the Different Ones!
    写点简单的思维题https://codeforces.com/problemset/problem/1927/D思路:用两个数组,一个存储原始数据,一个用nex存该位置第一次不一样的下标#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<sstream>#include<string>#include<str......
  • 1948.Educational Codeforces Round 163 - sol
    202403补题效率低下。场上发挥并不是很好,A~E都是简单的,而场上没有去推F的式子,只是找了找规律,然后发现是一个不可做的东西就下播了。如果直接推式子就会很快地做出来,还是非常可惜。A.SpecialCharactersYouaregivenaninteger\(n\).Yourtaskistobuildast......
  • Codeforces Round 920 (Div. 3)----->E. Eat the Chip
    一,思路:1.这是一道博弈论的题目(两个人都绝顶聪明,所以每个人都会按最优方案进行)。这题你会发现,两个人从一开始就已经确定了结局。2.如假如他们俩的棋子在竖直方向上距离相差的值是偶数,那么一定就两个结果Alice赢或者平局,反之奇数则是Bob赢或者平局(仔细分析一下就能得知)。3.所......
  • CF1943C - Tree Compass | 树的直径 思维
    links给定一棵\(n\)个点的树,可以执行任意次以下操作:选定一个距离\(u\),并将与\(u\)距离为\(d\)的点都染色。求使得所有节点都染上颜色的最小操作次数,并输出方案。\(n\leq2000\)看着数据范围,朝着\(O(n^2)\)的dp去想,但是没有想出来。然后又尝试大胆猜测,\(d\)只......
  • git worktree学习
    转自:https://blog.csdn.net/qq_35067322/article/details/1215514691.介绍当在一个仓储下,在A分支编译时,是不能切到B分支上工作的,只能等着A编译完成,很影响效率。所以可以使用worktree命令新建一个工作分支。步骤1:在A分支上编译中,使用以下命令新建一个目录。gitworktreeadd.......