Codeforces 842C Ilya And The Tree 树上gcd

题目链接

题意

给定一棵根为\(1\)的树。定义每个点的美丽值为根节点到它的路径上所有点的\(gcd\)值。但是对于每个点,在计算它的美丽值时,可以将这条路径上某个点的值变为\(0\)来最大化它的美丽值。现问每个点的美丽值最大是多少。

注意,每个点的美丽值计算是独立的,即每次可以选择变为\(0\)的点可以是不同的。

思路

对于某一条路径,考虑上面变化的点。

如果变为\(0\)的是,

根节点

那么可以直接一路往下ans0[v]=gcd(ans0[u],val[v]);(\(u\)\(v\)的父亲节点);

非根节点

如果不是根节点,而是中间不知道哪一个点,那该怎么办呢?

要想到的是,此时也是有一个不变量的,那就是根——根节点的权值始终不会改变,也就是说整条路径不管怎么变,最终的\(gcd\)值都是根节点的权值的因子

因此,可以预处理出根节点的所有因子,然后\(dfs\)的时候统计路径上的每个因子的个数。对于一个深度为\(dep\)的点来说,只有当根节点到它的路径上某个因子的出现次数\(\geq dep-1\),这个因子才可能是满足条件的\(gcd\). 从大到小枚举即可。

Code

#include <bits/stdc++.h>
#define maxn 200010
using namespace std;
typedef long long LL;
struct Edge {
    int to, ne;
    Edge(int _to=0, int _ne=0): to(_to), ne(_ne) {}
}edge[maxn * 2];
int tot, t, ne[maxn], ans0[maxn], ans1[maxn], val[maxn], cnt[maxn], divi[maxn];
void add(int u, int v) {
    edge[tot] = Edge(v, ne[u]);
    ne[u] = tot++;
}
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
void accum(int x, bool sgn) {
    for (int i = 0; i < t; ++i) {
        if (x % divi[i] == 0) if (sgn==1) ++cnt[i]; else --cnt[i];
    }
}
void dfs(int u, int fa, int dep) {
    for (int i = ne[u]; ~i; i = edge[i].ne) {
        int v = edge[i].to;
        if (v == fa) continue;
        ans0[v] = gcd(ans0[u], val[v]);
        accum(val[v], 1);
        for (int j = t-1; j >= 0; --j) if (cnt[j] >= dep) { ans1[v] = divi[j]; break; }
        dfs(v, u, dep+1);
        accum(val[v], 0);
    }
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
    memset(ne, -1, sizeof(ne));
    for (int i = 1; i < n; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y), add(y, x);
    }
    for (int i = 1; i*i <= val[1]; ++i) {
        if (i*i == val[1]) divi[t++] = i;
        else if (val[1]%i==0) divi[t++] = i, divi[t++] = val[1]/i;
    }
    ans0[1] = 0;
    sort(divi, divi+t);
    dfs(1, -1, 0);
    printf("%d", val[1]);
    for (int i = 2; i <= n; ++i) printf(" %d", max(ans0[i], ans1[i])); printf("\n");
    return 0;
}

posted @ 2017-10-14 16:32  救命怀  阅读(501)  评论(4编辑  收藏  举报