题意:给定一棵树,求这个节点的所有子树与它互质的节点(包括他本身)的个数.
http://acm.hdu.edu.cn/showproblem.php?pid=5468
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//int gcd(int a,int b){return b?gcd(b,a%b):a;}
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
using namespace std;
int n,a,b;
vector<int> prime_element[100005];
int y[100005],ans[100005],num[100005];//num[i]表示子树里因子为i的有多少个
int head[100005],e;
struct Edge{
int to,next;
}edge[100005*2];
void add(int u,int v)
{
edge[e].to=v;
edge[e].next=head[u];
head[u]=e++;
}
int calc(int p,int q){
int res=0;
for(int i=1;i<(1<<prime_element[p].size());i++){
int w=1;
int cnt=0;
for(int j=0;j<prime_element[p].size();j++){
if(i&(1<<j)){
cnt++; //这个因子由多少素因子构成
w*=prime_element[p][j];
}
}
if(cnt%2) //容斥
res+=num[w];
else
res-=num[w];
num[w]+=q; //q=1时,表示要退出这颗子树了,把根节点的因子算上
}
return res;
}
int dfs(int p,int q){
int pre=calc(y[p],0);
int s=0;
for(int i=head[p];~i;i=edge[i].next){
int v=edge[i].to;
if(v==q)
continue;
s+=dfs(v,p);
}
int now=calc(y[p],1);
ans[p]=s-(now-pre); //总结点-与根节点不互质节点数
if(y[p]==1)
ans[p]++; //是1的话它和本身也互质
return s+1;
}
int main(){
for(int i=2;i<=100000;++i){
if(!prime_element[i].empty())
continue;
for(int j=i;j<=100000;j+=i){
prime_element[j].push_back(i); //存放j的所有素因子【模板】
}
}
int cnt=0;
while(~scanf("%d",&n)){
e=0;
memset(num,0,sizeof(num));
memset(head,-1,sizeof(head));
for(int i=0;i<n-1;++i){
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
for(int i=1;i<=n;++i)
scanf("%d",&y[i]);
dfs(1,-1);
printf("Case #%d:",++cnt);
for(int i=1;i<=n;i++){
printf(" %d",ans[i]);
}
printf("\n");
}
}