原题:埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 B
题意:
给出n个点的价值,根为q,已经n-1条边,求下面这个数据的和%(1e9+7)
以i为根的子树中,val[i]的合约数的个数*i
合约数:合数且是约数
解析:
不能每个点分开算一遍,所以要想一个办法在一次遍历中解决所有问题
题目求的是一个结点为根的子树中所有合约数的个数,那么我们可以仿照前缀和的做法
首先预处理素数筛和每个数的合约数,放在vector<int>yin
里面,从root开始往下遍历,用map记录下所有数出现的次数。
假设p结点的价值是8,遍历到p之前已经有2个4,3个8,而等把p结点的子树遍历完后回溯到p的时候有4个4,4个8,那么就是说这棵子树包括了2个4,1个8
另外,质数不可能的合约数,也不可能有合约数,所以可以直接跳过
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<sstream>
#include<functional>
#define D long long
#define F double
#define MAX 0x7fffffff
#define MIN -0x7fffffff
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define pill pair<int, int>
#define for1(i,a,b) for(int i=a;i<=b;i++)
#define for2(i,a,b) for(int i=a;i>=b;i--)
#define ini(n) scanf("%d",&n)
#define inll(n) scanf("%lld",&n)
#define outisp(n) printf("%d ",n)
#define outllsp(n) printf("%lld ",n)
#define outiel(n) printf("%d\n",n)
#define outllel(n) printf("%lld\n",n)
using namespace std;
#define N 20100
#define mod ((int)1e7+7)
#define random(a,b) (rand()%(b-a+1)+a)
int ispri[N],pri[N],now;
vector<int>yin[N];
void init(){
ispri[1]=1;
for(int i=2;i<=N/2;i++)ispri[i]=1;
for(int i=2;i<=N/2;i++){
if(ispri[i])pri[++now]=i;
for(int j=1;j<=now&&pri[j]*i<=N/2;j++){
ispri[pri[j]*i]=0;
}
}
for(int i=4;i<=N/2;i++){
if(ispri[i])continue;
for(int j=4;j<=i;j++){
if(i%j==0&&!ispri[j])yin[i].push_back(j);
}
}
}
int n,ro;
vector<int>v[N];
int val[N],ans[N];
map<int,int>ti;
void dfs(int p,int f){
int vv=val[p];
if(!ispri[vv]){
int sum=0;
for(int i=0;i<yin[vv].size();i++){
int tmp=yin[vv][i];
sum+=ti[tmp];
}
ti[vv]++;
for(int i=0;i<v[p].size();i++){
if(v[p][i]==f)continue;
dfs(v[p][i],p);
}
int sum1=0;
for(int i=0;i<yin[vv].size();i++){
int tmp=yin[vv][i];
sum1+=ti[tmp];
}
ans[p]=sum1-sum;
}
else{
ans[p]=0;
for(int i=0;i<v[p].size();i++){
if(v[p][i]==f)continue;
dfs(v[p][i],p);
}
}
}
int main(){
init();
int t;scanf("%d",&t);while(t--){
scanf("%d%d",&n,&ro);
for(int i=1;i<=n;i++)v[i].clear();
ti.clear();
for(int i=1;i<n;i++){
int a,b;scanf("%d%d",&a,&b);
v[a].push_back(b);v[b].push_back(a);
}
for(int i=1;i<=n;i++){
scanf("%d",val+i);
}
dfs(ro,-1);
D anss=0;
for(int i=1;i<=n;i++){
anss=(anss+(D)ans[i]*(D)i)%mod;
}
printf("%lld\n",anss);
}
}