• 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("
    ");
        return 0;
    }
    
    
  • 相关阅读:
    14.Java基础_函数/函数重载/参数传递
    98. 验证二叉搜索树(深搜)
    13.Java基础_数组内存图
    12Java基础_数组定义格式/动态初始化/静态初始化
    计算几何基础
    11.Java基础_IDEA常用快捷键
    Add Two Numbers
    Two Sum
    登录界面id属性的使用
    系统查看
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/7667735.html
Copyright © 2020-2023  润新知