题意:
思路:
上面是官方题解,套路加树上启发式合并,就是这个启发式之前没写过,代码写的感觉有点繁琐。
总结:当碰到关于点对的lca具有某些性质时,可以考虑对于每个点,当这个点成为lca时求把这个点当作lca的点对对其的贡献。
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=101000;
vector<int>v[MAX_N],p[MAX_N];
int val[MAX_N],ans1[MAX_N];
long long ans2[MAX_N];
int size[MAX_N],wson[MAX_N];
long long cnt[MAX_N];
bool vis[MAX_N];
int maxx;
long long maxl;
void dfs1(int x,int fa){
size[x]=1;
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa)
continue;
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[wson[x]])
wson[x]=y;
}
}
void cal_ask(int x,int fa){
for(int i=0;i<p[val[x]].size();i++){
int y=p[val[x]][i];
if(y<maxx)
break;
if(cnt[y]!=0){
if(y==maxx){
maxl+=cnt[y];
break;
}
else if(y>maxx){
maxx=y;
maxl=cnt[y];
break;
}
}
}
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa||vis[y])
continue;
cal_ask(y,x);
}
}
void cal(int x,int fa,int vl){
for(int i=0;i<p[val[x]].size();i++){
int y=p[val[x]][i];
cnt[y]+=vl;
}
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa||vis[y])
continue;
cal(y,x,vl);
}
}
void cal(int x,int vl){
if(vl>0){
for(int i=0;i<p[val[x]].size();i++){
int y=p[val[x]][i];
if(y<maxx)
break;
if(cnt[y]!=0){
if(y==maxx){
maxl+=cnt[y];
break;
}
else if(y>maxx){
maxx=y;
maxl=cnt[y];
break;
}
}
}
}
for(int i=0;i<p[val[x]].size();i++){
int y=p[val[x]][i];
cnt[y]+=vl;
}
}
void dfs2(int x,int fa,int flag){
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa||y==wson[x])
continue;
dfs2(y,x,0);
}
if(wson[x]){
dfs2(wson[x],x,1);
vis[wson[x]]=true;
}
//cal(x,fa,1);
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa||y==wson[x])
continue;
cal_ask(y,x);
cal(y,x,1);
}
cal(x,1);
ans1[x]=maxx;ans2[x]=maxl;
maxx=maxl=0;
if(wson[x])
vis[wson[x]]=false;
if(!flag){
cal(x,fa,-1);
}
}
void init(){
for(int i=100000;i>=1;i--){
for(int j=i;j<=100000;j+=i)
p[j].push_back(i);
}
}
int main(void){
init();
int n,i,x,y;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
dfs1(1,0);
dfs2(1,0,0);
for(i=1;i<=n;i++)
printf("%d %lld\n",ans1[i],ans2[i]);
return 0;
}