hdu5468A Puzzled Elena (容斥原理+dfs序)

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;
}

猜你喜欢

转载自blog.csdn.net/sdauguanweihong/article/details/81675391