• hdu 6832 A Very Easy Graph Problem 构造树+dfs


    题意:

    给你一个n个点m条边的图,对于第i条边,它的长度是2i,对于每一个顶点,它不是0类型,就是1类型。你需要找出来对于所有的“两个不同类型的点之间最短距离”的和

    题解(参考:https://blog.csdn.net/wayne_lee_lwc/article/details/107851431):

    因为20+21+22<23,即20+21+...+2n-1<2n

    所以如果第i条边连接的两个点已经联通,我们就不需要用这条边。所以这里用并查集判断下

    后面我们用

    sum,以该节点为根的子树中所有黑白点对的距离和
    dp[0][0],子树中所有黑节点到该节点的距离和
    dp[0][1],子树中黑节点的数量
    dp[1][0],子树中所有白节点到该节点的距离和
    dp[1][1],子树中白节点的数量
    color,节点颜色

    dfs先统计一下最小的子树上上面个变量的值,然后再上升到更大的子树上进行综合统计

     

    代码+注释:

    #include<stack>
    #include<queue>
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    const int N = 1e6 + 50;
    const long long mod = 1e9 + 7;
    struct Edge
    {
        ll point;
        ll next;
        long long w;
    } nxt[N];
    struct Node
    {
        ll type;
        long long dp[2][2];
        long long sum;
    } node[N];
    ll fa[N];
    ll head[N];
    ll T,n,m,tot;
    ll finds(ll x)
    {
        if(x!=fa[x])
        {
            ll y=finds(fa[x]);
            return fa[x]=y;
        }
        return x;
    }
    long long ppow(ll p)
    {
        long long ans = 1;
        long long pow = 2;
        while(p)
        {
            if(p & 1) ans = (ans * pow) % mod;
            p >>= 1;
            pow = (pow * pow) % mod;
        }
        return ans;
    }
    void add_edge(ll x,ll y,long long w)
    {
        nxt[++tot] = {y,head[x],w};
        head[x] = tot;
    }
    /*
    sum,以该节点为根的子树中所有黑白点对的距离和
    dp[0][0],子树中所有黑节点到该节点的距离和
    dp[0][1],子树中黑节点的数量
    dp[1][0],子树中所有白节点到该节点的距离和
    dp[1][1],子树中白节点的数量
    color,节点颜色
    */
    void dfs(ll k,ll f)
    {
        node[k].dp[node[k].type][1] = 1;
    
        for(ll i = head[k],j; i; i = nxt[i].next)
        {
            j = nxt[i].point;
            if(j == f) continue;
            dfs(j,k);
            node[k].dp[0][0] = (node[k].dp[0][0] + node[j].dp[0][0] + (node[j].dp[0][1] * nxt[i].w) % mod) % mod;
            node[k].dp[1][0] = (node[k].dp[1][0] + node[j].dp[1][0] + (node[j].dp[1][1] * nxt[i].w) % mod) % mod;
            node[k].dp[0][1] += node[j].dp[0][1];
            node[k].dp[1][1] += node[j].dp[1][1];
            node[k].sum = (node[k].sum + node[j].sum) % mod;
        }
        long long sum0 = node[k].dp[0][0];
        long long cnt0 = node[k].dp[0][1];
        long long sum1 = node[k].dp[1][0];
        long long cnt1 = node[k].dp[1][1];
        long long w;
        /*
        比如k树下面有i,j两颗子树,那么i树上的白色点到j树上的黑色点的距离我们可以用:
        i树上的白色点到k树的距离加上j树上黑色点到k树的距离
        */
        for(ll i = head[k],j; i; i = nxt[i].next)
        {
            j = nxt[i].point;
            if(j == f) continue;
            w = nxt[i].w;
    
            //k树上的黑色节点数量,与子树j的白色节点,所有黑白队的距离和
            node[k].sum = (node[k].sum + ((cnt0 - node[j].dp[0][1]) * (node[j].dp[1][0] + w * node[j].dp[1][1])) % mod) % mod;
            //k树上的白色节点数量,与子树j的黑色节点,所有黑白队的距离和
            node[k].sum = (node[k].sum + ((cnt1 - node[j].dp[1][1]) * (node[j].dp[0][0] + w * node[j].dp[0][1])) % mod) % mod;
        }
    }
    int main()
    {
        cin >> T;
        while(T--)
        {
            tot = 1;
            scanf("%lld%lld",&n,&m);
            for(ll i = 1; i <= n; i++)
            {
                node[i] = {0,0,0,0,0,0};
                head[i] = 0;
                scanf("%lld",&node[i].type);
                fa[i] = i;
            }
            for(ll i = 1; i <= m; i++)
            {
                ll x,y;
                scanf("%lld%lld",&x,&y);
                //加了下面这个判断,那么1就肯定是我们构造的树的根节点
                if(x>y) swap(x,y);
                if(finds(x) == finds(y))
                    continue;
    
                add_edge(x,y,ppow(i));
                add_edge(y,x,ppow(i));
                fa[fa[y]] = fa[x];
            }
            dfs(1,0);
            cout << node[1].sum << endl;
        }
    }
  • 相关阅读:
    10_23自定义签发token,其他drf组件
    10_22频率认证和jwt
    10_21 三大认证
    vue2.0实现过滤
    windows下零基础gulp构建
    vue1.0+vue2.0实现选项卡
    数组去重方法
    stop()在animate中的用法
    两边固定,中间自适应
    JS获取宽度高度大集合
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13456990.html
Copyright © 2020-2023  润新知