1. 程式人生 > >hdu 5468(莫比烏斯+搜尋)

hdu 5468(莫比烏斯+搜尋)

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

題意:在一棵樹上,每個節點有值,求以x為根節點的樹中,有多少與根節點互質

思路:

用num[i]記錄節點中包含因子i的個數,然後搜尋到當前根節點時,我們先記錄下在此之前的num,然後遍歷返回後,

計算num的差值,利用莫比烏斯原理,先ans記錄樹中所有的節點數,然後該加的加,該減的減。

莫比烏斯不清楚的話可以翻翻前面的文章。

參考以下大大博文:

/*
如果互質,找出子樹中包含val[cur]的因子的數,假設為6,則減去約數中含有2,3的
但是會重複減去含有6的,所以應該在加上含6的數
於是滿足了莫比烏斯函式,合數為0,含奇數個質數為-1,含偶數個質數為1
感覺特別適合容斥原理。


對於dfs序:/*並不瞭解,也可以做的
將樹展現在陣列上。
void DFS(int u, int fa)  
{  
    dfn ++;  
    seq[dfn] = u;  
    for(int i = HEAD[u]; i != -1; i = E[i].next)  
    {  
        int v = E[i].to;  
        if(v != fa)  
            DFS(v, u);  
    }  
    dfn ++;  
    seq[dfn] = -u;  
}

參考:
AOQNRMGYXLMV:http://www.cnblogs.com/AOQNRMGYXLMV/p/4858452.html
Tc_To_Top:http://blog.csdn.net/tc_to_top/article/details/48802683
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <functional>
typedef long long ll;
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 100000;


int is_prime[maxn+10];
int prime[maxn+10];
int mu[maxn+10];
int snum[maxn+10];
vector<int> fac[maxn + 10];
vector<int> F[maxn+10];
int tot;
void Moblus()
{
    tot = 0;
    memset(is_prime,0,sizeof(is_prime));
    mu[1] = 1;
    for(int i = 2; i <= maxn; i++)
    {
        if(!is_prime[i])
        {
            prime[tot++] = i;
            mu[i] = -1;
        }

        for(int j = 0; j < tot; j++)
        {
            if(prime[j]*i>maxn)
                break;
            is_prime[i*prime[j]] = 1;
            if(i % prime[j])
            {
                mu[i*prime[j]] = -mu[i];
            }
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
    for(int i = 2; i <= maxn; i++)
    {
        if(mu[i])
            for(int j = i; j <= maxn; j+=i)
                fac[j].push_back(i);
    }
}

int val[maxn],num[maxn],ans[maxn];


void dfs(int cur,int par)
{
    snum[cur] = 1;
    vector<int>tt;
    for(int i = 0; i<fac[val[cur]].size(); i++)
    {
        int v = fac[val[cur]][i];
        tt.push_back(num[v]);
        num[v]++;

    }
    for(int i = 0; i < F[cur].size(); i++)
    {
        int v = F[cur][i];
        if(v == par)
            continue;
        dfs(v,cur);
        snum[cur] += snum[v];
    }
    ans[cur] = snum[cur];
    for(int i = 0; i<fac[val[cur]].size(); i++)
    {
        int v = fac[val[cur]][i];
        int c = num[v]-tt[i];
        if(c)
            ans[cur] += mu[v]*c;

    }
}

void ini()
{
    tot=  0;
    memset(ans,0,sizeof(ans));
    memset(num,0,sizeof(num));
    //memset(head,-1,sizeof(head));
}

int main()
{
    int n;
    Moblus();
    int cas = 1,a,b;
    while(scanf("%d",&n) != EOF)
    {
        ini();
        for(int i = 0;i <= n;i++)
        F[i].clear();
        for(int i = 0; i <n-1; i++)
        {
            scanf("%d%d",&a,&b);
            F[a].push_back(b);
            F[b].push_back(a);
        }
        for(int i = 1 ; i <= n; i++)
            scanf("%d",&val[i]);
        dfs(1,0);
        printf("Case #%d:",cas++);

        for(int i = 1; i <= n; i++)
        {
            printf(" %d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}