小睿睿的伤害(树上启发式合并)
小睿睿的伤害
题目大意:
一颗树,有点权,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;
}
小睿睿的伤害(树上启发式合并)相关推荐
- 牛客挑战赛42 B.小睿睿的伤害(树上启发式合并)
题意: 思路: 上面是官方题解,套路加树上启发式合并,就是这个启发式之前没写过,代码写的感觉有点繁琐. 总结:当碰到关于点对的lca具有某些性质时,可以考虑对于每个点,当这个点成为lca时求把这个点当 ...
- 【学习笔记】树上启发式合并
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 树上启发式合并 模板 复杂度分析 例题 **Problem A. Arpa's letter-m ...
- (树上启发式合并)CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/CF741D Pro ...
- 2020CCPC(长春) - Strange Memory(树上启发式合并+位运算)
题目大意:给出一棵 n 个点组成的有根树,一号节点是根节点,现在要求实现 n * n 的公式: 题目分析:树上启发式合并,需要修改部分内部实现,如果可以想到树启的话,那么应该往子树上去靠拢,当每个点作 ...
- CodeForces - 375D Tree and Queries(树上启发式合并)
题目链接:点击查看 题目大意:给出一棵有根树,每个节点都有一个编号代表颜色,现在给出m个询问,每个询问的形式为u k,需要回答以u为根节点的子树中,数量超过k的颜色有多少种 题目分析:树上启发式合并模 ...
- CodeForces - 600E Lomsat gelral(树上启发式合并)
题目链接:点击查看 题目大意:给出一棵树,每个节点都有一个编号代表一种颜色,现在对于每个子树求出现最多的颜色的编号之和 题目分析:因为n给到了1e5,看完这个题第一反应就是暴力n*n,但显然是会超时的 ...
- [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)
文章目录 前言 树上启发式合并 引入 算法思想 时间复杂度 模板 练习 例题:CF600E Lomsat gelral solution code CF208E Blood Cousins solut ...
- 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)
Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...
- 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)
题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...
最新文章
- Spring 详解(三):AOP 面向切面的编程
- 生成建表脚本up_CreateTable
- 用python简单处理图片(4):图像中的像素访问
- 后端 java ee_刷新器-Java EE 7后端十大功能
- react学习(56)--常见HTTP错误
- metadata.js
- ASP.NET Core 用户注册 - ASP.NET Core 基础教程 - 简单教程,简单编程
- 「leetcode」110.平衡二叉树(详解)
- 数据库连接池c3p0
- 笔记本电脑突然搜索不到无线网信号怎么办?
- 字节跳动 数据分析 一轮技术面
- 天河二号超级计算机能买到吗,天河二号计算机是巨型机吗
- 音频数据的建模全流程代码示例:通过讲话人的声音进行年龄预测
- windows防火墙 程序_如何允许应用程序通过Windows防火墙进行通信
- gitlab修改时区
- Android数据持久化保存--File
- early fusion VS later fusion
- 每日一练1.直接排序法
- ubuntu linux下制作win10启动盘
- mysql 格式化时间 年月日时分秒与年月日字符串作比较