HDU 5468 Puzzled Elena(DFS序+容斥原理)

题目链接:传送门

题意:

给定一棵树,求这个节点的所有子树中包括他本身与它互质的节点的个数。

分析:转自传送门

因为每个数的大小<=100000 这个范围内   2*3*5*7*11*13 *17> 100000 最多只有 6 个素因子。   

当我们知道这个怎么处理以后,我们可以利用dfs序,解决这个问题

我们求当前这个节点的答案时,用容斥搞就是:以这个节点为根的树的大小 - 有1个素因子和他相同的节点个数 + 有2个素因子和他相同的个数 - 有3个素因子和他相同的个数 ....

那么问题来了,我们如何求出有多少个 有1个素因子和他相同的个数,有2个素因子和他相同的个数 ,,,,,

我们维护一个数fac[]数组,fac[i] 代表包含因子i的节点个数。

那么在这颗树中,进入这颗树之前求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),离开这颗树的时候再求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),他们的差便是我们需要的(子树中的和他有关系的信息)。

到这里,问题就解决了,容斥版的做法 时间复杂度 O(n*2^6 + nlogn) :

代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

int fac[maxn];

int w[maxn];
int ans[maxn];

struct Graph{
    vector<int >vc[maxn];
    void init(){
        for(int i=0;i<maxn;i++)
            vc[i].clear();
    }
    void add(int u,int v){
        vc[u].push_back(v);
    }
}G1,G2;

void prepare(){
    G1.init();
    for(int i=2;i<maxn;i++){
        if(G1.vc[i].size())
            continue;
        for(int j=i;j<maxn;j+=i)
            G1.add(j,i);
    }
}

int calc(int u,int x){
    int ans = 0,n=G1.vc[u].size();
    for(int i=1;i<(1<<n);i++){
        int tot=1,cnt=0;
        for(int j=0;j<n;j++){
            if((1<<j)&i){
                cnt++;
                tot=tot*G1.vc[u][j];
            }
        }
        if(cnt&1)
            ans = ans+fac[tot];
        else
            ans = ans-fac[tot];
        fac[tot]+=x;
    }
    return ans;
}

int dfs(int u,int pre){
    int cnt = 0;
    int L = calc(w[u],0);
    for(int i=0;i<G2.vc[u].size();i++){
        int v = G2.vc[u][i];
        if(v==pre) continue;
        cnt+=dfs(v,u);
    }
    int R = calc(w[u],1);
    ans[u]=cnt-(R-L);
    if(w[u]==1) ans[u]++;
    return cnt+1;
}

int main()
{
    prepare();
    int n,cas=1;
    while(~scanf("%d",&n)){
        G2.init();
        memset(fac,0,sizeof(fac));
        int u,v;
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            G2.add(u,v);
            G2.add(v,u);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",w+i);
        dfs(1,0);
        printf("Case #%d: ",cas++);
        for(int i=1;i<=n;i++){
            printf("%d%c",ans[i],i==n? '\n':' ');
        }
    }
    return 0;
}




你可能感兴趣的:(HDU 5468 Puzzled Elena(DFS序+容斥原理))