题目大意:
一颗树,有点权,1为根。
问:一个点作为两个点的
L
C
A
LCA
LCA且
G
C
D
GCD
GCD最大,这样的对数。(建议看原题)
思路:
当固定一个点
u
u
u作为
L
C
A
LCA
LCA时,贡献有两部分。
1.以
u
u
u为根的两条不同链上的点。
2.
u
u
u和其他任意点。
找到所有对数的最大
G
C
D
GCD
GCD,个数就是答案。
考虑预处理所有点的答案,又是子树问题,启发式合并即可。
两数最大
G
C
D
GCD
GCD,即最大公因子,点权都在
1
e
5
1e5
1e5以内,预处理所有点权的因子,合并信息时,直接合并因子即可。
合并信息:
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){ // 更新maxn
maxn=it,re=num[it];
}
else if(it==maxn){ // 更新个数
re+=num[it];
}
}
}
}
启发式合并主体:
单条链更新答案和合并信息一定要分开(同一条链上两点
L
C
A
LCA
LCA不一定是当前的
u
u
u)
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;
}