csu 1811 Tree Intersection 2016湖南省赛 I

2023-11-07

Problem

acm.csu.edu.cn/csuoj/problemset/problem?pid=1811

vjudge.net/contest/161962#problem/I

Reference

blog.csdn.net/qwb492859377/article/details/52436186

www.cnblogs.com/fightfordream/p/6801852.html

Meaning

一棵 n 个结点的树,每个结点都有一种颜色,问对与树上的每条边,删掉它之后得到的两棵树中,共有的颜色有多少种(在那两棵树中都有的颜色就是公有的颜色)

Analysis

首先规定 1 号结点为整棵树的根(其它号也可以)。

对与每一条边,就看成是某个结点于它的父结点的连边,于是,删掉这条边后两个连同块的共有颜色数,就等价于以这个结点为根的子树里共有颜色数(只有两个连通块,其中一个连通块的“公共颜色”即是两个连同块的公共颜色)。

公共颜色是什么呢?假如在其中一个连通块中有 2 个绿色结点,而原树一共有 4 个结点是绿色的,那绿色就是这两个连通块的公共颜色之一;反之,这个连通块有一个黑色结点,而原树也总共只有一个黑色结点,那黑色就是这个连通块“私有”的颜色。

怎么统计一棵子树里的共有颜色数呢?可以用线段树。先不考虑空间,对每个结点都建一棵线段树,记录共有颜色数,然后将所有子结点的树合并到父结点的树里,就得到了父结点的答案。但这么做空间太大。

但其实对每个结点都没必要真的建一整棵树,因为根结点只有一种颜色,只需要一条链,而子树的信息,可以重用子树建出来的结点,这样就可以开得下。

具体看代码理解吧,线段树新姿势啊。

Code

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100000;

struct edge
{
	int to, nxt;
} e[N<<1];

struct node
{
	int lc, rc; // 左、右子结点的位置
	int com; // 这棵树中共有颜色的数量
	int num; // 对叶子有用,表示这棵树中这种颜色的结点数
} tree[18*N]; // 存树结点的空间

int sz; // 树结点总数
int c[N+1]; // 结点i的颜色
int sum[N+1]; // 颜色i的总数
int head[N+1]; // 前向星链头
int root[N+1]; // 为第i个结点建的线段树的根所在位置
int ans[N]; // 答案数组

void add_edge(int f, int t, int id)
{
	e[id].to = t;
	e[id].nxt = head[f];
	head[f] = id;
}

inline void pushup(int x)
{
	/* 不是叶子的结点,只需记录共有颜色的数量 */
	tree[x].com = tree[tree[x].lc].com + tree[tree[x].rc].com;
}

int build(int c, int l, int r)
{
	int rt = ++sz;
	tree[rt].lc = tree[rt].rc = tree[rt].num = 0;
	if(l == r)
	{
		tree[rt].num = 1;
		tree[rt].com = tree[rt].num < sum[c];
	}
	else
	{
		int m = l + r >> 1;
		/* 不需要建整棵树,只要建一条链 */
		if(c > m)
			tree[rt].rc = build(c, m+1, r);
		else
			tree[rt].lc = build(c, l, m);
		pushup(rt);
	}
	return rt;
}

void merge(int &fa, int ch, int l, int r)
{
	if(!fa || !ch)
	{
		/* 若父结点那棵线段树的这个结点为空,
		 * 就直接重用子结点的线段树的这条链
		 */
		if(!fa)
			fa = ch;
		return;
	}
	if(l != r)
	{
		int m = l + r >> 1;
		merge(tree[fa].lc, tree[ch].lc, l, m);
		merge(tree[fa].rc, tree[ch].rc, m+1, r);
		pushup(fa);
	}
	else
	{
		/* 将子树里这种颜色的结点数加到父结点的树 */
		tree[fa].num += tree[ch].num;
		/* 这种颜色的结点不全在这棵树中,
		 * 则这种颜色是共有颜色
		 */
		tree[fa].com = tree[fa].num < sum[l];
	}
}

void dfs(int rt, int fa, int eid, int n)
{
	/* 先给根结点“建棵树” */
	root[rt] = build(c[rt], 1, n);
	for(int i=head[rt]; ~i; i=e[i].nxt)
	{
		if(e[i].to == fa)
			continue;
		/* 先递归处理子结点 */
		dfs(e[i].to, rt, i, n);
		/* 然后将子结点信息合并上来 */
		merge(root[rt], root[e[i].to], 1, n);
	}
	/* 加边时同一条边加了两次,
	 * 这个映射找出此边在输入时的序号
	 */
	if(rt != 1)
		ans[eid/2+1] = tree[root[rt]].com;
}

int main()
{
	tree[0].lc = tree[0].rc = tree[0].com = tree[0].num = 0;
	int n;
	while(~scanf("%d", &n))
	{
		memset(sum, 0, sizeof sum);
		for(int i=1; i<=n; ++i)
		{
			scanf("%d", c+i);
			++sum[c[i]];
		}
		memset(head, -1, sizeof head);
		for(int i=1, a, b, id=0; i<n; ++i)
		{
			scanf("%d%d", &a, &b);
			add_edge(a, b, id++);
			add_edge(b, a, id++);
		}
		sz = 0;
		memset(root, 0, sizeof root);
		dfs(1, 0, 0, n);
		for(int i=1; i<n; ++i)
			printf("%d\n", ans[i]);
	}
	return 0;
}

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

csu 1811 Tree Intersection 2016湖南省赛 I 的相关文章

  • 算法与数据结构(二十五)TopK问题:基于快排的Python模板

    首先 先写partition模板 def partition nums left right pivot nums left 初始化一个待比较数据 i j left right while i lt j while i
  • 分治—快速选择算法

    文章目录 215 数组中的第K个最大元素 1 题目 2 算法原理 3 代码实现 LCR 159 库存管理 III
  • 算法设计与实现--动态规划篇

    什么是动态规划算法 动态规划算法是一种求解复杂问题的方法 通过将原问题分解为相对简单的子问题来求解 其基本思想是将待求解的问题分解为若干个子问题 阶段 按顺序求解子阶段 前一子问题的解 为后一子问题的求解提供了有用的信息 在求解任一子问题时
  • C语言,求取数组的序亏:已知一个整数数组,求出个数组中每个元素在整个 数组的排序。

    要求获取整数数组中每个元素的排序 可以使用以下方法 1 定义一个结构体数组 其中每个结构体包含数组元素的值和索引 2 遍历整数数组 将每个元素与其索引一起存储到结构体数组中 3 对结构体数组进行排序 按照元素的值进行升序排序 4 遍历排序后
  • 不会做的题汇总

    摘苹果 题目描述 小红来到苹果园 帮园长摘苹果 园长请小红把摘完的苹果的最小的那个去掉 如果有 多个最小的苹果 那么都要去掉 剩余的苹果算一下平均一个苹果有多重 平均重 量请保留1位小数 输入 输入有2行 第一行 一个整数n代表小红摘的n个
  • C/C++查找算法-----------------------二分查找详解

    二分查找 定义 实例 定义 二分查找也称折半查找 搜索过程从数组的中间元素开始 如果中间元素正好是要查找的元素 则搜索过程结束 如果某一特定元素大于或者小于中间元素 则在数组大于或小于中间元素的那一半中查找 而且跟开始一样从中间元素开始比较
  • 二叉树(接口函数的实现)

    今天继续来分享的是二叉树 我们废话不多说 直接来看下面的几个接口函数 然后我们把他们实现 我们就掌握二叉树的二分之一 今天粉丝破千了 属实有点高兴了 typedef char BTDataType typedef struct Binary
  • 八大排序(插入排序 | 选择排序 | 冒泡排序)

    在我们内存中我们一般会有一些没有顺序的数据 我们成为内排序 而今天分享八大排序的是时间复杂度为O N 2 的插入排序 选择排序和教学意义比较强的冒泡排序 插入排序 这是插入排序的动图 通过动图我们也是可以看到我们的插入排序的思想 从当前的位
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • c 关于数组几个查序程序

    1 查询某元素是否在数组中 int main void char i 10 2 1 7 2 10 5 2 0 1 4 10 10 1 3 1 0 8 char z 10 1 2 3 4 1 4 6 8 0 9 int zz 0 标志位 0
  • List去重-使用distinctByKey方法根据对象的属性进行去重

    description 使用distinctByKey方法根据对象的属性进行去重 author zs date 2023 12 18 14 29 param keyExtractor return java util function Pr
  • 面试150-13(Leetcode238除自身以外数组的乘积)

    代码 class Solution public int productExceptSelf int nums int n nums length int res new int n int product 1 int zerocnt 0
  • 回溯算法第零篇【递归、搜索与回溯】【回溯算法入门必看】

    本篇文章的目的 1 给小伙伴们对回溯算法中的名词进行解释 2 消除递归的恐惧 回溯是递归的一个分支 给小伙伴们一个建议 整篇文章都要看完 一字不漏 全是干货 注意 分析回溯的思想之前 我们得知道一个关系 递归包含搜索 搜索包含回溯 所以我们
  • 【数据结构和算法】 K 和数对的最大数目

    其他系列文章导航 Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一 题目描述 二 题解 2 1 方法一 双指针排序 三 代码 3 1 方法一 双指针排序 3
  • 剑指 Offer(第2版)面试题 40:最小的 k 个数

    剑指 Offer 第2版 面试题 40 最小的 k 个数 剑指 Offer 第2版 面试题 40 最小的 k 个数 解法1 排序 解法2 快速选择 解法3 优先队列 剑指 Offer 第2版 面试题 40 最小的 k 个数 题目来源 53
  • LeetCode 2397. 被列覆盖的最多行数,状态压缩优化回溯法

    一 题目 1 题目描述 给你一个下标从 0 开始 大小为 m x n 的二进制矩阵 matrix 另给你一个整数 numSelect 表示你必须从 matrix 中选择的 不同 列的数量 如果一行中所有的 1 都被你选中的列所覆盖 则认为这
  • 【数据结构和算法】小行星碰撞

    其他系列文章导航 Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一 题目描述 二 题解 2 1 什么情况会用到栈 2 2 方法一 模拟 栈 三 代码 3 1
  • 搜索二叉树(BSTree)

    一 搜索二叉树的概念 二叉搜索树又称为做二叉排序树 二叉查找树 其要么是一棵空树 要么是一个满足以下性质的二叉树 若它的左子树不空 则左子树上所有结点的关键字均小于根结点关键字 若它的右子树不空 则右子树上所有结点的关键字均大于根结点关键字
  • 链表的中间节点

    链表的中间节点 力扣 LeetCode 官网 全球极客挚爱的技术成长平台 备战技术面试 力扣提供海量技术面试资源 帮助你高效提升编程技能 轻松拿下世界 IT 名企 Dream Offer https leetcode cn problems
  • 数据结构——排序

    前言 哈喽小伙伴们好久不见 也是顺利的考完试迎来了寒假 众所周知 不怕同学是学霸 就怕学霸放寒假 假期身为弯道超车的最佳时间 我们定然是不能懒散的度过 今天我们就一起来学习数据结构初阶的终章 七大排序 本文所有的排序演示都为升序排序 目录

随机推荐