小睿睿的伤害

题目大意:

一颗树,有点权,1为根。
问:一个点作为两个点的LCALCALCA且GCDGCDGCD最大,这样的对数。(建议看原题)

思路:

当固定一个点uuu作为LCALCALCA时,贡献有两部分。
1.以uuu为根的两条不同链上的点。
2.uuu和其他任意点。
找到所有对数的最大GCDGCDGCD,个数就是答案。
考虑预处理所有点的答案,又是子树问题,启发式合并即可。

两数最大GCDGCDGCD,即最大公因子,点权都在1e51e51e5以内,预处理所有点权的因子,合并信息时,直接合并因子即可。
合并信息:

int num[N],ans1[N],ans2[N],maxn=0,re=0;
queue<int> p;
int flag[N];void insert(int x){for(auto it:res[x]){  // x的因子num[it]++;if(flag[it]==0){ // 标记位置,用来清空p.push(it);flag[it]=1;}}
}

更新答案:

void update(int x){for(auto it:res[x]){if(num[it]){  // 其他链上存在if(it>maxn){  // 更新maxnmaxn=it,re=num[it];}else if(it==maxn){ // 更新个数re+=num[it];}}}
}

启发式合并主体:
单条链更新答案和合并信息一定要分开(同一条链上两点LCALCALCA不一定是当前的uuu)

void dfs2(int now,int last){for(auto it:ve[now]){if(it==last||it==son[now]) continue;  dfs2(it,now); // 先走轻儿子clear();  // 清空信息}if(son[now]) dfs2(son[now],now);  // 走重儿子不清空for(auto it:ve[now]){if(it==last||it==son[now]) continue;add(it,now,1),add(it,now,2); // 更新答案,合并轻儿子}update(val[now]); insert(val[now]); // u结点一定要加上ans1[now]=maxn,ans2[now]=re;maxn=0,re=0;  // 这个点有意思
}

特别想说的一点:

 update(val[now]); insert(val[now]);ans1[now]=maxn,ans2[now]=re;maxn=0,re=0; // 就这个

答案都是全局变量,一般只在清空轻儿子时初始化,此题比较特殊,各点相互独立,故在每个点记录后,都要初始化。

Code:

#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=1e5+10;
vector<int> ve[N];
vector<int> res[N];
int n,val[N];void init(int num){int maxn=sqrt(num*1.0);for(int i=1;i<=maxn;i++){int s1=i,s2=num/i;if(num%i==0){res[num].push_back(s1);if(s2!=s1) res[num].push_back(s2);}}
}int son[N],_size[N];
void dfs1(int now,int last){_size[now]=1; int maxn=0;for(auto it:ve[now]){if(it==last) continue;dfs1(it,now);_size[now]+=_size[it];if(_size[it]>maxn){maxn=_size[it],son[now]=it;}}
}int num[N],ans1[N],ans2[N],maxn=0,re=0;
queue<int> p;
int flag[N];void insert(int x){for(auto it:res[x]){num[it]++;if(flag[it]==0){p.push(it);flag[it]=1;}}
}void update(int x){for(auto it:res[x]){if(num[it]){if(it>maxn){maxn=it,re=num[it];}else if(it==maxn){re+=num[it];}}}
}void add(int now,int last,int op){if(op==1) update(val[now]);else insert(val[now]);for(auto it:ve[now]){if(it!=last){add(it,now,op);}}
}void clear(){while(!p.empty()){int u=p.front(); p.pop();num[u]=0,flag[u]=0;}maxn=0,re=0;
}void dfs2(int now,int last){for(auto it:ve[now]){if(it==last||it==son[now]) continue;dfs2(it,now);clear();}if(son[now]) dfs2(son[now],now);//cout<<now<<" "<<son[now]<<endl;//for(int i=1;i<=12;i++){//   cout<<i<<" "<<num[i]<<endl;//}//cout<<endl;for(auto it:ve[now]){if(it==last||it==son[now]) continue;add(it,now,1),add(it,now,2);}update(val[now]); insert(val[now]);ans1[now]=maxn,ans2[now]=re;maxn=0,re=0;
}int main(){guo312;cin>>n;for(int i=1;i<n;i++){int u,v; cin>>u>>v;ve[u].push_back(v);ve[v].push_back(u);}for(int i=1;i<=n;i++){cin>>val[i];if(res[val[i]].size()==0){init(val[i]);}}dfs1(1,0),dfs2(1,0);for(int i=1;i<=n;i++){cout<<ans1[i]<<" "<<ans2[i]<<endl;}return 0;
}

小睿睿的伤害(树上启发式合并)相关推荐

  1. 牛客挑战赛42 B.小睿睿的伤害(树上启发式合并)

    题意: 思路: 上面是官方题解,套路加树上启发式合并,就是这个启发式之前没写过,代码写的感觉有点繁琐. 总结:当碰到关于点对的lca具有某些性质时,可以考虑对于每个点,当这个点成为lca时求把这个点当 ...

  2. 【学习笔记】树上启发式合并

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 树上启发式合并 模板 复杂度分析 例题 **Problem A. Arpa's letter-m ...

  3. (树上启发式合并)CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/CF741D Pro ...

  4. 2020CCPC(长春) - Strange Memory(树上启发式合并+位运算)

    题目大意:给出一棵 n 个点组成的有根树,一号节点是根节点,现在要求实现 n * n 的公式: 题目分析:树上启发式合并,需要修改部分内部实现,如果可以想到树启的话,那么应该往子树上去靠拢,当每个点作 ...

  5. CodeForces - 375D Tree and Queries(树上启发式合并)

    题目链接:点击查看 题目大意:给出一棵有根树,每个节点都有一个编号代表颜色,现在给出m个询问,每个询问的形式为u k,需要回答以u为根节点的子树中,数量超过k的颜色有多少种 题目分析:树上启发式合并模 ...

  6. CodeForces - 600E Lomsat gelral(树上启发式合并)

    题目链接:点击查看 题目大意:给出一棵树,每个节点都有一个编号代表一种颜色,现在对于每个子树求出现最多的颜色的编号之和 题目分析:因为n给到了1e5,看完这个题第一反应就是暴力n*n,但显然是会超时的 ...

  7. [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)

    文章目录 前言 树上启发式合并 引入 算法思想 时间复杂度 模板 练习 例题:CF600E Lomsat gelral solution code CF208E Blood Cousins solut ...

  8. 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)

    Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...

  9. 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)

    题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi​,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...

最新文章

  1. Spring 详解(三):AOP 面向切面的编程
  2. 生成建表脚本up_CreateTable
  3. 用python简单处理图片(4):图像中的像素访问
  4. 后端 java ee_刷新器-Java EE 7后端十大功能
  5. react学习(56)--常见HTTP错误
  6. metadata.js
  7. ASP.NET Core 用户注册 - ASP.NET Core 基础教程 - 简单教程,简单编程
  8. 「leetcode」110.平衡二叉树(详解)
  9. 数据库连接池c3p0
  10. 笔记本电脑突然搜索不到无线网信号怎么办?
  11. 字节跳动 数据分析 一轮技术面
  12. 天河二号超级计算机能买到吗,天河二号计算机是巨型机吗
  13. 音频数据的建模全流程代码示例:通过讲话人的声音进行年龄预测
  14. windows防火墙 程序_如何允许应用程序通过Windows防火墙进行通信
  15. gitlab修改时区
  16. Android数据持久化保存--File
  17. early fusion VS later fusion
  18. 每日一练1.直接排序法
  19. ubuntu linux下制作win10启动盘
  20. mysql 格式化时间 年月日时分秒与年月日字符串作比较

热门文章

  1. rust新版组队指令_新版rust指令是啥啊?
  2. 关于EDP触摸屏使用笔记
  3. mysql导入bak文件
  4. K8SEASY:一键安装K8S高可用集群
  5. 怎样测试mysql最大并发量_如何测试一台服务器的最大并发量?
  6. 卡通动漫Mac动态壁纸5K
  7. 【毕业设计】java ssm会议室预约管理系统
  8. 那天,妹子给我发来了一串乱码…
  9. XSS-Lab闯关笔记
  10. 航迹关联--目标跟踪