博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Problem E. TeaTree - HDU - 6430 (树的启发式合并)
阅读量:4557 次
发布时间:2019-06-08

本文共 1396 字,大约阅读时间需要 4 分钟。

题意

有一棵树,每个节点有一个权值。

任何两个不同的节点都会把他们权值的\(gcd\)告诉他们的\(LCA\)节点。问每个节点被告诉的最大的数。

题解

第一次接触到树的启发式合并

用一个set维护每个节点权值的因子。

自下而上,把每一个节点和所有儿子分别合并,记录他们的最大的\(gcd\)(即两个集合合并时找到的最大的公共因子),并更新答案即可。

计算因子的时候,如果你对于每个权值都找一遍因子,那么时间复杂度是\(n\sqrt{n}\)的。所以可以提前预处理,是\(n\log(n)\)的。

代码

#include 
#define FOPI freopen("in.txt", "r", stdin)#define FOPO freopen("out.txt", "w", stdout)using namespace std;typedef long long LL;const int maxn = 1e5 + 100;int n;set
S[maxn];vector
v[maxn], Y[maxn];int ans[maxn];int merge(int x, int y){ int res = 0; if (S[x].size() < S[y].size()) swap(S[x], S[y]); for (int it : S[y]) { if (S[x].count(it)) res = max(res, it); else S[x].insert(it); } S[y].clear(); return res;}void dfs(int x){ for (int y : v[x]) { dfs(y); ans[x] = max(ans[x], merge(x, y)); }}void init(){ for (int i = 1; i <= 1e5; i++) for (int j = i; j <= 1e5; j += i) Y[j].push_back(i);}int main(){ memset(ans, -1, sizeof(ans)); init(); int x; scanf("%d", &n); for (int i = 2; i <= n; i++) scanf("%d", &x), v[x].push_back(i); for (int i = 1; i <= n; i++) { scanf("%d", &x); for (int j : Y[x]) S[i].insert(j); } dfs(1); for (int i = 1; i <= n; i++) printf("%d\n", ans[i]);}

转载于:https://www.cnblogs.com/ruthank/p/10910443.html

你可能感兴趣的文章
《区块链100问》笔记整理——42~49问
查看>>
使用Jquery+EasyUI 进行框架项目开发案例讲解之二---用户管理源码分享
查看>>
深入理解计算机系统(1.4)---并发与并行、浅谈抽象
查看>>
函数依赖的公理化系统
查看>>
rabbitmq学习(四):利用rabbitmq实现远程rpc调用
查看>>
侯捷C++学习(二)
查看>>
EasyPlayer RTSP Android安卓播放器修复播放画面卡在第一帧bug
查看>>
web项目中全局常量的添加
查看>>
搬运工程 启动!
查看>>
局部加权回归(LWR) Matlab模板
查看>>
Connect to the DSP on C6A8168/DM8168/DM8148 using CCS
查看>>
hibernate在使用getCurrentSession时提示no session found for current thread
查看>>
【Luogu1471】方差(线段树)
查看>>
DEV中svg图标的使用
查看>>
Codefroces Gym101572 I.Import Spaghetti-有向图跑最小环输出路径(Floyd)
查看>>
有关位运算的操作+二进制状态压缩
查看>>
Eclipse插件 -- 阿里巴巴扫描编码规插件
查看>>
(1.1)学习笔记之mysql体系结构(内存、进程、线程)
查看>>
markdown测试
查看>>
Java-Maven-Runoob:Maven 依赖管理
查看>>