zoukankan      html  css  js  c++  java
  • codeforces1156D 0-1-Tree 换根dp

    题目传送门

    题意:

      给定一棵n个点的边权为0或1的树,一条合法的路径(x,y)(x≠y)满足,从x走到y,一旦经过边权为1的边,就不能再经过边权为0的边,求有多少边满足条件?

    思路:

      首先,这道题也可以用并查集的做法过,点这里

      那换根dp怎么写呢?

      设$f[u]$为以1为根,自下而上到$u$的末节点是1的合法路径数量,$g[u]$代表以1为根,自下而上到$v$末节点是0的合法路径数量,这个可以通过一遍dfs简单求解。

      再设$nf[u]$和$ng[u]$代表以u为根的两种合法路径数量,进行换根dfs,在换根的过程中:

      若某一条边是0边,则:

        $ng[st.to]=ng[u]$,$nf[st.to]=f[st.to]$。这个方程也很好理解,白边的路径是不会变的,所有从父节点自上而下转移过来的黑边到了这里都是非法路径了。

      若某一条边是1边,则:

        $ng[st.to]=g[st.to]$,$nf[st.to]=nf[u]-g[st.to]+ng[u]$,白边只有从下往上过来的了。黑边要减去  到当前位置为白边与父节点的黑边连接形成的边 ,再加上父节点是白边,加上黑边形成的边。

    #pragma GCC optimize (2)
    #pragma G++ optimize (2)
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include<bits/stdc++.h>
    #include<cstdio>
    #include<vector>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dep(i,b,a) for(int i=b;i>=a;i--)
    #define clr(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    #define pii pair<int,int >
    using namespace std;
    typedef long long ll;
    const int maxn=200010;
    ll rd()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int T;
    struct edge{
        int to,w;
    };
    vector<edge>ve[maxn];
    int f[maxn],g[maxn],nf[maxn],ng[maxn];
    int n,m;
    ll ans;
    void dfs_1(int u,int fa){
        for(auto &st:ve[u]){
            if(st.to==fa)continue;
            dfs_1(st.to,u);
            if(st.w==0){
                g[u]+=g[st.to]+1;
            }else{
                f[u]+=f[st.to]+1+g[st.to];
            }
        }
    }
    void dfs_2(int u,int fa){
        ans+=nf[u]+ng[u];
        for(auto &st:ve[u]){
            if(st.to==fa)continue;
            if(st.w==0){
                ng[st.to]=ng[u];
                nf[st.to]=f[st.to];
            }else{
                ng[st.to]=g[st.to];
                nf[st.to]=nf[u]-g[st.to]+ng[u];
            }
            dfs_2(st.to,u);
        }
    }
    int main(){
        cin>>n;
        rep(i,1,n-1){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            ve[u].pb({v,w});
            ve[v].pb({u,w});
        }
        dfs_1(1,0);
        nf[1]=f[1],ng[1]=g[1];
        dfs_2(1,0);
        cout<<ans<<endl;
    } 
    View Code
  • 相关阅读:
    一致性哈希算法
    Discourse 的标签(Tag)只能是小写的原因
    JIRA 链接 bitbucket 提示错误 Invalid OAuth credentials
    JIRA 如何连接到云平台的 bitbucket
    Apache Druid 能够支持即席查询
    如何在 Discourse 中配置使用 GitHub 登录和创建用户
    Apache Druid 是什么
    Xshell 如何导入 PuTTYgen 生成的 key
    windows下配置Nginx支持php
    laravel连接数据库提示mysql_connect() :Connection refused...
  • 原文地址:https://www.cnblogs.com/mountaink/p/11597906.html
Copyright © 2011-2022 走看看