zoukankan      html  css  js  c++  java
  • CF1088F Ehab and a weird weight formula 贪心 倍增

    CF1088F Ehab and a weird weight formula

    题意

    给定一棵树,点有点权,其中这棵树满足除了权值最小的点外,每个点至少有一个点权小于它的相邻点。
    要求你重新构建这棵树,使得代价最小。计算代价的方法如下:

    • 点的代价: (deg_xv_x),其中(deg_x)表示点(x)的度
    • ((x, y))的代价:(log_2(dis(x, y)) cdot min(v_x, v_y)),其中(dis(x, y))表示(x)(y)在原树中的距离。

    树的代价为点的代价与边的代价之和。

    题解

    首先我们来证明一个事情:为了满足每个点至少有一个点权小于它的相邻点(除了权值最小的点之外),这棵树必须满足:根为权值最小的点,对于每个点而言,父亲的权值一定小于它。
    如果一个点x要依靠它的儿子y来满足这个性质,那么就意味着它的儿子y也需要依靠它的某个儿子z来满足这个性质。
    那么这样的话,叶节点就无论如何都不能满足这个性质了。得证。

    那么这个性质可以为我们带来什么?
    首先我们考虑不断插入节点来构建出这棵树。那么一个点(x)选择(fa)作为他的父亲,带来的贡献为:
    (v_x + v_{fa} + log_2(dis(x, fa)) cdot min(v_xv_{fa}))
    如果一个点(x)选中了它子树中的某个点作为父亲,那么它还不如选择距离更小的祖先,代价更小。
    如果一个点(x)选中了深度小于它的非祖先节点,那么它还不如从它选择的这个节点往上走,走到一个离它最近的,是(x)的祖先的节点,那么这个新节点肯定比原来选择的节点距离(x)更近,且权值更小,所以显然更优。
    因此点(x)一定会选择它的某个祖先,因为(log_2)的值可以看做是一段一段的,我们可以用倍增来维护每一段中的最小值,而因为越往上越小,所以这个最小值刚好就是它的第(2^k)级祖先,因此对于某个点,我们只需要倍增的跳一跳,在这些可能的点中选择一个最优的就可以了。
    当然如果祖先的个数不够(2^k)的话就需要取root作为father

    #include<bits/stdc++.h>
    using namespace std;
    #define R register int
    #define LL long long
    #define AC 500100
    #define ac 1000100
    #define inf 100000000000000000LL
    
    int n, rot;
    LL ans;
    int v[AC], fa[AC][20];
    int Head[AC], date[ac], Next[ac], tot;
    
    inline int read()
    {
        int x = 0;char c = getchar();
        while(c > '9' || c < '0') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    
    inline void upmin(LL &a, LL b) {if(b < a) a = b;}
    inline void upmax(LL &a, LL b) {if(b > a) a = b;}
    
    inline void add(int f, int w)
    {
        date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot;
        date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot;
    }
    
    void pre()
    {
        n = read(), rot = 1;
        for(R i = 1; i <= n; i ++) 
        {
            v[i] = read();
            if(v[i] < v[rot]) rot = i;
        }
        for(R i = 2; i <= n; i ++) add(read(), read());
    }
    
    void dfs(int x)
    {
        LL rnt = inf;
        if(x != rot)
        {	
            for(R i = 0; i <= 19; i ++) 
            {	
                if(i) fa[x][i] = fa[fa[x][i - 1]][i - 1];
                upmin(rnt, 1LL * (i + 1) * v[fa[x][i]] + v[x]);
            }
            ans += rnt;
        }
        else for(R i = 0; i <= 19; i ++) fa[x][i] = x;
        for(R i = Head[x]; i; i = Next[i])
        {
            int now = date[i];
            if(now == fa[x][0]) continue;
            fa[now][0] = x, dfs(now);
        }
    }
    
    int main()
    {
    //	freopen("in.in", "r", stdin);
        pre();
        dfs(rot);
        printf("%lld
    ", ans);
    //	fclose(stdin);
        return 0;
    }
    
  • 相关阅读:
    asp.net gridview中增加单击单元格事件
    asp.net在应用母版的页面下采用了ModalPopupExtender弹出窗中应用autocomplete
    网站发布后无法访问,提示“/”应用程序中的服务器错误
    asp.net将数据导出到excel
    看完让你彻底搞懂Websocket原理
    PL/SQL简单使用——导入、导出数据表
    Java 定时任务的几种实现方式
    用element-ui 时,报value.getTime is not a function错误:
    Object.assign()解释整理
    IntelliJ IDEA2017 激活方法 最新的(亲测可用)
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10551913.html
Copyright © 2011-2022 走看看