Puzzled Elena HDU - 5468 (容斥定理+前缀和)

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≤n≤105)

, after that has n−1 lines, each line has two numbers a and b (1≤a,b≤n), representing that vertex a is connect with vertex b. Then the next line has n numbers, the ith number indicates the value of the ith vertex. Values of vertices are not less than 1 and not more than 105

.

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

递归里面可以开数组,但是不能开太大,要不然会爆栈的

一棵树的每个节点的 因子是有限的, 我们不可能遍历一棵树好多次,所以我们考虑  

容斥定理+前缀和(一般很多的话,差值很常见)

对于一个节点,我们知道他的子树一共有n个点,那么和 子树的根不互质的,就是有他的各个因子的数量。

#include
using namespace std;
typedef long long LL;
#pragma comment(linker, “/STACK:1024000000,1024000000”) 
#define rep(i,a,b) for(int i=a;i=a;--i)

const int N=1e5+10;

vector vec[N];
bool vis[N];
void init(){
	for(int i=2;i

还有一种就是直接预处理在 递归体里面做的拆分(也就是莫比乌斯)

#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 100000;

int mu[maxn + 10], pcnt, prime[maxn];
bool vis[maxn + 10];
vector factors[maxn + 10];
vector G[maxn + 10];

void init() {
    pcnt = 0;
    mu[1] = 1;
    for(int i = 2; i <= maxn; i++) {
        if(!vis[i]) {
            mu[i] = -1;
            prime[pcnt++] = i;
        }
        for(int j = 0; j < pcnt && i * prime[j] <= maxn; j++) {
            vis[i * prime[j]] = true;
            if(i % prime[j] != 0) mu[i * prime[j]] = -mu[i];
            else {
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }

	//如果mu[i]不为0,说明他是 单个素因子的乘积 
    for(int i = 2; i <= maxn; i++) if(mu[i])   for(int j = i; j <= maxn; j += i) factors[j].push_back(i);
}

int val[maxn + 10];
int n;

int cnt[maxn], sz[maxn], ans[maxn];

void dfs(int u, int fa) {
    sz[u] = 1;
    vector pre;
    for(int d : factors[val[u]]) {
        pre.push_back(cnt[d]);//保留下他在遍历子树之前的因子的sum值 
        cnt[d]++;
    }
    for(int v : G[u]) {
        if(v == fa) continue;
        dfs(v, u);
        sz[u] += sz[v];
    }
    ans[u] = sz[u];
    for(int i = 0; i < factors[val[u]].size(); i++) {
        int d = factors[val[u]][i];
        int c = cnt[d] - pre[i];
        if(c) ans[u] += mu[d] * c;
    }
}

int main()
{
    init();

    int kase = 1;
    while(scanf("%d", &n) == 1 && n) {
        for(int i = 1; i <= n; i++) G[i].clear();

        for(int u, v, i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i = 1; i <= n; i++) scanf("%d", val + i);

        memset(cnt, 0, sizeof(cnt));
        dfs(1, 0);

        printf("Case #%d:", kase++);
        for(int i = 1; i <= n; i++) printf(" %d", ans[i]);
        printf("\n");
    }

    return 0;
}

 

你可能感兴趣的:(【ACM-数论】,....容斥原理,.....莫比乌斯反演)