首页 > 其他分享 >[HackerRank] Unique Colors

[HackerRank] Unique Colors

时间:2023-09-27 16:44:09浏览次数:32  
标签:HackerRank int siz void Colors dfn res Unique define

原题

对于一个树上问题,我们显然先考虑链上怎么做

多种颜色链上还是不会做怎么办?考虑只有黑白两种颜色

我们发现这个问题正着难算,我们就考虑用 $n \times m - $ 不满足条件的颜色个数,其中 \(m\) 为颜色种类

我们发现对于一个固定的点,他的答案即为 \(2n -\) 这个点所在的黑色连通块大小 \(-\) 这个点所在的白色连通块大小

i  : 1  2  3  4  5  6  7  8  9  10
ci : 0  0  1  0  0  1  1  1  0  0
sz0: 2  2  0  2  2  0  0  0  2  2
sz1: 0  0  1  0  0  3  3  3  0  0
ans: 18 18 19 18 18 17 17 17 18 18

然后我们再考虑回多个颜色段的问题,我们发现对于每种颜色,他是独立的。意思就是我们枚举当前考虑某个颜色,我们就可以把 \(c_i\) 变成是这个颜色不是这个颜色两种,这就变成了黑白颜色的问题

i  : 1  2  3  4  5  6  7  8  9  10
ci : 0  0  1  2  2  1  0  2  2  1
sz0: 0  0  4  4  4  4  0  3  3  3
sz1: 2  2  0  2  2  0  3  3  3  0
sz2: 3  3  3  0  0  2  2  0  0  1
ans: 25 25 23 24 24 24 25 24 24 26

然后我们用同样的思想,对于固定某个颜色 \(c_i\) ,他在树上的贡献就是不经过颜色为 \(c_i\) 的点时连通块的大小,而产生贡献的部分就是这个连通块中所有的点

然后问题就变成了求这些连通块。我们考虑现在在 \(u\) 点,则我们可以通过 \(dfs\) 求出对于 \(u\) 点的每个儿子,在向下遍历到 \(x\) 时,若路径 \(x \rightarrow u\) 上没有一个颜色 \(c_u\) 且 \(c_x = c_u\) ,则把 \(x\) 加入 \(S_{son_u}\) 这个集合中。

容易发现,我们可以通过 \(dfs\) 序 + 容斥原理来让这些连通块加上一个值。具体的,我们让 \(u\) 点子树加上一个答案,然后再在 \(S_u\) 这个集合中的点的子树内减去这个答案。这可以差分实现

最终还要记得处理以 \(1\) 为根的连通块的情况

最终复杂度 \(O(n)\)

我说的可能不清楚,给下代码:

#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define pcn putchar('\n')
#define ll long long
#define LL __int128
#define MP make_pair
#define fi first
#define se second
#define gsize(x) ((int)(x).size())
#define Min(a, b) (a = min(a, b))
#define Max(a, b) (a = max(a, b))
#define For(i, j, k) for(int i = (j), END##i = (k); i <= END##i; ++ i)
#define For__(i, j, k) for(int i = (j), END##i = (k); i >= END##i; -- i)
#define Fore(i, j, k) for(int i = (j); i; i = (k))
//#define random(l, r) ((ll)(rnd() % (r - l + 1)) + l)
using namespace std;

namespace IO {
	template <typename T> T read(T &num) {
		num = 0;
		T f = 1;
		char c = ' ';
		while(c < 48 || c > 57) if((c = getchar()) == '-') f = -1;
		while(c >= 48 && c <= 57) num = (num << 1) + (num << 3) + (c ^ 48), c = getchar();
		return num *= f;
	}
	ll read() {
		ll num = 0, f = 1;
		char c = ' ';
		while(c < 48 || c > 57) if((c = getchar()) == '-') f = -1;
		while(c >= 48 && c <= 57) num = (num << 1) + (num << 3) + (c ^ 48), c = getchar();
		return num * f;
	}
	template <typename T> void Write(T x) {
		if(x < 0) putchar('-'), x = -x;
		if(x == 0) {
			putchar('0');
			return ;
		}
		if(x > 9) Write(x / 10);
		putchar('0' + x % 10);
		return ;
	}
	void putc(string s) {
		int len = s.size() - 1;
		For(i, 0, len) putchar(s[ i ]);
	}
	template <typename T> void write(T x, string s = "\0") {
		Write( x ), putc( s );
	}
}
using namespace IO;

/* ====================================== */

const int maxn = 1e5 + 50;

int n;
int a[ maxn ];
struct Graph {
	struct Edge {
		int v, nxt;
	} edge[ maxn << 1 ];
	int head[ maxn ], cnt = 1;

	void addedge(int u, int v) {
		edge[ ++ cnt ] = Edge {v, head[ u ]};
		head[ u ] = cnt;
	}
	void Addedge(int u, int v) {
		addedge(u, v);
		addedge(v, u);
	}
} G;
int dfn[ maxn ], times, siz[ maxn ];
int buc[ maxn ];
vector<int> dwn[ maxn ], col[ maxn ];
ll ans[ maxn ];

void dfs(int u, int father) {
	int t = buc[ a[ u ] ]; // 存储备份信息 
	if(t) dwn[ t ].push_back(u);
	if(!t || u == 1) col[ a[ u ] ].push_back(u); // 特判以1为根 
	dfn[ u ] = ++ times, siz[ u ] = 1;
	Fore(i, G.head[ u ], G.edge[ i ].nxt) {
		int v = G.edge[ i ].v;
		if(v == father) continue;
		buc[ a[ u ] ] = v;// buc[ i ]的定义 
		dfs(v, u);
		siz[ u ] += siz[ v ];
	}
	buc[ a[ u ] ] = t; // 还原备份 
}

void upd(int l, int r, int k) { // 差分修改区间 
	if(l > r) return ;
	ans[ l ] += k;
	ans[ r + 1 ] -= k;
}

void mian() {
	read(n);
	For(i, 1, n) read(a[ i ]);
	int u, v;
	For(i, 2, n) {
		read(u), read(v);
		G.Addedge(u, v);
	}
	buc[ a[ 1 ] ] = 1; // buc[ i ]:存储颜色i的点的儿子 
	dfs(1, 0);
	For(i, 1, n) {
		int res = siz[ i ];
		for(auto j : dwn[ i ]) res -= siz[ j ];
		upd(dfn[ i ], dfn[ i ] + siz[ i ] - 1, res);
		for(auto j : dwn[ i ]) upd(dfn[ j ], dfn[ j ] + siz[ j ] - 1, -res);
		res = siz[ 1 ];
		for(auto j : col[ i ]) res -= siz[ j ];
		upd(1, n, res);
		for(auto j : col[ i ]) upd(dfn[ j ], dfn[ j ] + siz[ j ] - 1, -res);
	}
	For(i, 1, n) ans[ i ] += ans[ i - 1 ];
	For(i, 1, n) write(1ll * n * n - ans[ dfn[ i ] ], "\n");
}

void init() {

}

void treatment() {

}

int main() {

#ifdef ONLINE_JUDGE
#else
	freopen("data.in", "r", stdin);
//	freopen("data.out", "w", stdout);
#endif

	treatment();
	int T = 1;
//	read(T);
	while(T --) {
		init();
		mian();
	}

	return 0;
}

标签:HackerRank,int,siz,void,Colors,dfn,res,Unique,define
From: https://www.cnblogs.com/fox-konata/p/17733064.html

相关文章

  • 【刷题笔记】63. Unique Paths II
    题目Arobotislocatedatthetop-leftcornerofa m x n grid(marked'Start'inthediagrambelow).Therobotcanonlymoveeitherdownorrightatanypointintime.Therobotistryingtoreachthebottom-rightcornerofthegrid(marked'......
  • How to fix Tailwind CSS colors not work in Next.js All In One
    HowtofixTailwindCSScolorsnotworkinNext.jsAllInOneTailwindCSS&Next.js13errorimporttype{Config}from'tailwindcss'constconfig:Config={content:['./src/pages/**/*.{js,ts,jsx,tsx,mdx}','......
  • unique
    uniqueunique是c++标准函数库之一,需要配合头文件#include<algorithm>使用作用:‘去掉’容器中相邻元素的重复元素,伪去除,相当于将重复元素添加到容器末尾使用前提:容器内元素必须有序结果:返回最后一个不重复元素的地址下标inta[N];intdis=unique(a,a+n)-a;//d......
  • [转]Mysql中普通索引key 、主键索引(primary key) 、唯一索引(unique key)与index区别
    原文地址:Mysql中普通索引key、主键索引(primarykey)、唯一索引(uniquekey)与index区别-元小疯-博客园一、索引的定义和由来:    索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行。 ......
  • PPT主题颜色ColorFormat、ColorScheme、ColorEffect 对象在PPT中的使用
    一、ColorFormat对象代表单色对象的颜色、带有过渡或图案填充的对象的前景或背景色,或者指针的颜色。可以将颜色设为显式的红-绿-蓝值(使用RGB属性)或设为配色方案中的一种颜色(使用SchemeColor属性)。使用下表中列出的属性之一返回ColorFormat对象。使用此属性对此对象如......
  • a build cache key that uniquely defines the task’s outputs based on its inputs
    BuildCachehttps://docs.gradle.org/current/userguide/build_cache.htmlTheGradle buildcache isacachemechanismthataimstosavetimebyreusingoutputsproducedbyotherbuilds.Thebuildcacheworksbystoring(locallyorremotely)buildoutputsan......
  • [LeetCode][62]unique-paths
    ContentThereisarobotonanmxngrid.Therobotisinitiallylocatedatthetop-leftcorner(i.e.,grid[0][0]).Therobottriestomovetothebottom-rightcorner(i.e.,grid[m-1][n-1]).Therobotcanonlymoveeitherdownorrightatanypointi......
  • LeetCode[62]UniquePaths
    ContentThereisarobotonanmxngrid.Therobotisinitiallylocatedatthetop-leftcorner(i.e.,grid[0][0]).Therobottriestomovetothebottom-rightcorner(i.e.,grid[m-1][n-1]).Therobotcanonlymoveeitherdownorrightatanypointi......
  • No_62_UniquePaths
    ContentThereisarobotonanmxngrid.Therobotisinitiallylocatedatthetop-leftcorner(i.e.,grid[0][0]).Therobottriestomovetothebottom-rightcorner(i.e.,grid[m-1][n-1]).Therobotcanonlymoveeitherdownorrightatanypointi......
  • C# 获取Windows系统设备唯一标识方法及代码(Unique Identifier)
    唯一的标识一个设备是一个基本功能,可以拥有很多应用场景,比如软件授权(如何保证你的软件在授权后才能在特定机器上使用)、软件License,设备标识,设备身份识别等。一、网卡MAC地址     MAC地址可能是最常用的标识方法,但是现在这种方法基本不可靠:一个电脑可能存在多个网卡,多个......