首页 > 其他分享 >P5588 小猪佩奇爬树

P5588 小猪佩奇爬树

时间:2022-11-07 14:45:00浏览次数:60  
标签:Map 小猪 Color int Num maxn Edge 佩奇 P5588

感谢所有AC

传送门

思路

       画图得到四种情况,无色,单色,多色同链(两端点),多色不同链(多端点)。

代码

#include<iostream>
#define maxn 1000100
using namespace std;
typedef long long ll;
int Map_Color[maxn], Color_Num[maxn], Subtree_Size[maxn], Cnt_Color_Num[maxn],
EndPoint_Num[maxn], EndPoint_Size[maxn], Lastpos_Color[maxn], cnt, Head[maxn], n;
ll Ans1[maxn], Ans2[maxn];
struct Edge {
	int to, nxt;
}G[maxn << 1];
//需要注意到,链式前向星存树时需要开结点数两倍空间 
//而在存图时要开边数两倍空间
void Add_Edge(int u, int v)
{
	G[++cnt].to = v;
	G[cnt].nxt = Head[u];
	Head[u] = cnt;
}
void Dfs(int u, int fa)
{
	int Subtree_Same_Color = 0, Pos_Same_Color = 0;
	//分别用来记录以u为根时,其出现同色点的子树个数和位置
	int Visit_Color_Num = Cnt_Color_Num[Map_Color[u]];
	//记录当前访问的结点的颜色已被访问的次数
	Subtree_Size[u] = 1;
	for (int i = Head[u]; i; i = G[i].nxt)
	{
		int v = G[i].to;
		if (v == fa)
			continue;
		int Now_Color_Num = Cnt_Color_Num[Map_Color[u]];
		//遍历当前子树前该颜色出现次数
		Dfs(v, u);
		Ans1[u] += 1ll * Subtree_Size[u] * Subtree_Size[v];
		//乘法原理求单色点的方案数
		Subtree_Size[u] += Subtree_Size[v];
		//计算完方案数后再算子树大小
		if (Now_Color_Num != Cnt_Color_Num[Map_Color[u]])
			Subtree_Same_Color++, Pos_Same_Color = v;
		//如果在搜索完子树v后发现有同色点,增加子树个数并记录位置
	}
	Ans1[u] += 1ll * (n - Subtree_Size[u]) * Subtree_Size[u];
	//u结点的另一部分和u的子树部分的方案计算
	if (Visit_Color_Num || (Cnt_Color_Num[Map_Color[u]] + 1) ^ Color_Num[Map_Color[u]])
		Subtree_Same_Color++;
	//如果最初访问时该颜色已经被访问过子树个数增加(因为说明以父结点那一部分的子树中有同色点)
	//如果该结点不是最后一个该颜色结点,那么说明与u的祖先结点的子树中也有同色点
	Cnt_Color_Num[Map_Color[u]]++;
	//记录当前颜色结点出现次数
	if (Subtree_Same_Color == 1)//只有一棵子树有同色点才可能成为端点
	{
		int EndPoint_Count_Size = 0;
		//u点作为端点时该端的计算值
		if (Pos_Same_Color)
			EndPoint_Count_Size = n - Subtree_Size[Pos_Same_Color];
		else
			EndPoint_Count_Size = Subtree_Size[u];
		if (!EndPoint_Num[Map_Color[u]])
			EndPoint_Size[Map_Color[u]] = EndPoint_Count_Size;
		//如果这个端点为该颜色第一个端点,则将计算值存入待计算数组中
		else if (EndPoint_Num[Map_Color[u]] == 1)
			Ans2[Map_Color[u]] = 1ll * EndPoint_Count_Size * EndPoint_Size[Map_Color[u]];
		//如果这个端点为该颜色第二个端点,计算出答案
		EndPoint_Num[Map_Color[u]]++;
		//统计端点数量
	}
	return;
}
int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> Map_Color[i];
		Color_Num[Map_Color[i]]++;
		Lastpos_Color[Map_Color[i]] = i;
		//分别记录颜色的映射,某种颜色总数,最后一次出现该颜色的位置(为求单颜色答案)
	}
	for (int i = 1, u, v; i < n; i++)
	{
		cin >> u >> v;
		Add_Edge(u, v);
		Add_Edge(v, u);
	}
	Dfs(1, 0);
	for (int i = 1; i <= n; i++)
	{
		if (!Color_Num[i])//没有该颜色结点
			cout << 1ll * n * (n - 1) / 2 << '\n';
		else if (Color_Num[i] == 1)//单一颜色结点
			cout << Ans1[Lastpos_Color[i]] << '\n';
		else if (EndPoint_Num[i] == 2)//有且只有两个端点
			cout << Ans2[i] << '\n';
		else//三个及以上个端点
			cout << 0 << '\n';
	}
	return 0;
}

 

标签:Map,小猪,Color,int,Num,maxn,Edge,佩奇,P5588
From: https://www.cnblogs.com/xqk0225/p/16865899.html

相关文章

  • 小猪佩奇的4种python玩法,带你趣味学python!
    本文说明为什么要学习python?是因为不仅社会上很多工作需要用到python,同时我们可以利用python做很多好玩儿的事儿,比如说:利用爬虫数据进行数据分析,得到一些有趣的结论;利用pyth......
  • 小猪学Java篇十九(Java基础语法------------Java基础语法总结)
    Java基础语法总结一,大纲:所学内容 (一),注释,标识符,关键字(二)、数据类型(三),类型转换(四),变量,常量(五),运算符(六),包机制,JavaDoc  二,逐个回顾(一),注释,标识符,关键......
  • 小猪学Java篇二十六(Switch多选择结构)
     packagecom.zhu.struct;publicclassSwitchDemo01{publicstaticvoidmain(String[]args){//case:【穿透现象】switch匹配一个具体的值,和if......
  • 一只特别脏的小猪生活在茂密的森
    http://ds.163.com/article/6337f4a2880c710001946382/http://ds.163.com/feed/6337f4a2880c710001946382/http://ds.163.com/article/6337f4a485eece000184a7f7/http://ds.......
  • 题解【P5588 hegm 爬树】
    题目传送门。来一个不一样的工程做法。我们直接对于每一个颜色\(i\)建虚树,显然可以通过树形DP来判断颜色\(i\)的节点是否在一条路径上。原题。然后存一下这条路径......
  • leetcode458 可怜的小猪
    思路:数学。实现:classSolution{public:intpoorPigs(intbuckets,intminutesToDie,intminutesToTest){intbase=minutesToTest/minutesToDie+1......