Since both Stefan and Damon fell in love with Elena, and it was really difficult for her to choose. Bonnie, her best friend, suggested her to throw a question to them, and she would choose the one who can solve it.
Suppose there is a tree with n vertices and n - 1 edges, and there is a value at each vertex. The root is vertex 1. Then for each vertex, could you tell me how many vertices of its subtree can be said to be co-prime with itself?
NOTES: Two vertices are said to be co-prime if their values’ GCD (greatest common divisor) equals 1.
Input
There are multiply tests (no more than 8).
For each test, the first line has a number n (1≤n≤1051≤n≤105), after that has n−1 lines, each line has two numbers a and b (1≤a,b≤n)(1≤a,b≤n), representing that vertex a is connect with vertex b. Then the next line has n numbers, the ith number indicates the value of the ith vertex. Values of vertices are not less than 11 and not more than .
Output
For each test, at first, please output “Case #k: “, k is the number of test. Then, please output one line with n numbers (separated by spaces), representing the answer of each vertex.
Sample Input
5
1 2
1 3
2 4
2 5
6 2 3 4 5
Sample Output
Case #1: 1 1 0 0 0
思路:当时做这题的idea其实是联想到今年山东acm省赛热身赛的B题(当时做掉这题,我们的rank就直接到第5了,在正赛造了报应,,,),我们先考虑一个问题,先解决如何在一堆整数集合当中找到互质的个数,可以考虑枚举,但是在树上做这个必然会T,我换了一个角度而是去观察每个数具有什么属性,这个就是容斥,属性的个数是有多少个sqare-free number是他的因子。极端情况是26−126−1个,即这个数是2∗3∗5∗7∗11∗132∗3∗5∗7∗11∗13的连乘,这种情况是最坏的情况,复杂度虽然O(n)O(n),但是常数就很大,但是目测还是可以过掉,优化的地方是因为case稍多,所以可以预处理一下每个数的sqare-free number,可以筛一下莫比乌斯函数来做,同时也需要莫比乌斯函数来容斥答案。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define ll long long
#define maxx 100005
using namespace std;
vector<int> fac[maxx];
int mu[maxx];
bool p[maxx];
int prime[maxx],cnt;
void init()
{
p[1]=mu[1]=1;
for(int i=2;i<maxx;i++)
{
if(!p[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<=maxx;j++)
{
p[i*prime[j]]=true;
if(i%prime[j])
mu[i*prime[j]]=-mu[i];
else
{
mu[i*prime[j]]=0;
break;
}
}
}
for(int i=2;i<maxx;i++)
{
if(mu[i]==0)continue;
for(int j=i;j<maxx;j+=i)
fac[j].push_back(i);
}
}
int head[maxx],to[maxx<<1],_next[maxx<<1],edge;
int c[maxx];
void addEdge(int x, int y)
{
to[++edge]=y,_next[edge]=head[x],head[x]=edge;
to[++edge]=x,_next[edge]=head[y],head[y]=edge;
}
int n;
int a[maxx];
int total;
int ans[maxx];
void dfs(int u,int fa)
{
int num=a[u];
int temp=total;
for(int i=0;i<fac[num].size();i++)
{
if(mu[fac[num][i]]==-1)temp-=c[fac[num][i]];
else temp+=c[fac[num][i]];
}
for(int i=head[u];i;i=_next[i])
{
int v=to[i];
if(v==fa)continue;
dfs(v,u);
}
++total;
for(int i=0;i<fac[num].size();i++) ++c[fac[num][i]];
ans[u]=total;
for(int i=0;i<fac[num].size();i++)
{
int _fac=fac[num][i];
if(mu[_fac]==-1)ans[u]-=c[_fac];
else ans[u]+=c[_fac];
}
ans[u]-=temp;
}
void _init()
{
total=0;
edge=0;
memset(head,0,sizeof(head));
memset(c,0,sizeof(head));
}
int main()
{
init();
int cal=1;
int x,y;
while(scanf("%d",&n)==1)
{
_init();
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
addEdge(x,y);
}
for(int i=1;i<=n;i++)
scanf("%d",a+i);
dfs(1,0);
printf("Case #%d:",cal++);
for(int i=1;i<n;i++)printf(" %d",ans[i]);
printf(" %d\n",ans[n]);
}
return 0;
}