Problem Description
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 \leq n \leq 10^5)$, after that has $n-1$ lines, each line has two numbers a and b $(1 \leq a,b \leq n)$, representing that vertex a is connect with vertex b. Then the next line has n numbers, the $i^{th}$ number indicates the value of the $i^{th}$ vertex. Values of vertices are not less than 1 and not more than $10^5$.
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
题意:
给定一棵树,求这个节点的所有子树中包括他本身与它互质的节点的个数。
分析:(转自大神博客)
当我们知道这个怎么处理以后,我们可以利用dfs序,解决这个问题
我们求当前这个节点的答案时,用容斥搞就是:以这个节点为根的树的大小 - 有1个素因子和他相同的节点个数 + 有2个素因子和他相同的个数 - 有3个素因子和他相同的个数 ....
那么问题来了,我们如何求出有多少个 有1个素因子和他相同的个数,有2个素因子和他相同的个数 ,,,,,
我们维护一个数fac[]数组,fac[i] 代表包含因子i的节点个数。
那么在这颗树中,进入这颗树之前求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),离开这颗树的时候再求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),他们的差便是我们需要的(子树中的和他有关系的信息)。
#include<iostream>
#include<cstdio>
#include<Cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 100005
int cnt;
vector<int>prime[maxn];
int vis[maxn];
int num[maxn];
int head[maxn];
int ans[maxn];
int y[maxn];
struct node
{
int v,next;
}edge[maxn*2];
void init()
{cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void fenjie()
{memset(vis,0,sizeof(vis));
for(int i=2;i<maxn;i++)
if(!vis[i])
for(int j=i;j<maxn;j+=i)
{
vis[j]=1;
prime[j].push_back(i);
}
}
int cal(int p,int q)
{
int sum=0;
for(int i=1;i<(1<<prime[p].size());i++)
{
int f=0,val=1;
for(int j=0;j<prime[p].size();j++)
if(i&(1<<j))
{
f++;
val*=prime[p][j];
}
if(f&1)
sum+=num[val];
else
sum-=num[val];
num[val]+=q;
}
return sum;
}
int dfs(int p,int q)
{
int pre=cal(y[p],0);
int s=0;
for(int i=head[p];~i;i=edge[i].next)
{
int v=edge[i].v;
if(v==q)
continue;
s+=dfs(v,p);
}
int now=cal(y[p],1);
ans[p]=s-(now-pre);
if(y[p]==1)
ans[p]++;
return s+1;
}
int main()
{fenjie();
int t=0;
int n,a,b;
while(~scanf("%d",&n))
{init();
++t;
memset(num,0,sizeof(num));
memset(ans,0,sizeof(ans));
for(int i=1;i<=n-1;i++)
{scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);}
for(int i=1;i<=n;i++)
scanf("%d",&y[i]);
dfs(1,-1);
printf("Case #%d:",t);
for(int i=1;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}