zoukankan      html  css  js  c++  java
  • [CF1156D] 0-1-Tree

    [CF1156D] 0-1-Tree - 并查集

    Description

    给定 n 个点的边权为 0 或 1 的树,一条合法的 x->y 路径满足一旦经过 1 边就不能再经过 0 边(换言之边权必须单调不降),求满足条件的路径数量。

    Solution

    所有答案点对有三种情况:全 0,全 1,一些 0 + 一些 1

    前两种可以用并查集直接处理掉,假设这个 0 连通块中的点数为 x,那么贡献为 x(x-1),1 同理

    对于第三种,枚举从 0 转 1 的点 i,假设这个 0 连通块中的点数为 x,假设这个 1 连通块中的点数为 y,则贡献为 (x-1)(y-1)

    顺便说一下 dp 思路的基本想法:设 (f[i][0/1/2/3]) 表示自底(未必是叶子)到 i 的各种路径的条数,计算出 f 后,根据 f 讨论合并方式计算答案(似乎更容易想到就是细节颇多)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    struct DSU
    {
        int fa[N], sz[N];
        int find(int p)
        {
            return p == fa[p] ? p : fa[p] = find(fa[p]);
        }
        void merge(int p, int q)
        {
            p = find(p);
            q = find(q);
            if (p != q)
                fa[p] = q;
        }
        void solve(int n)
        {
            for (int i = 1; i <= n; i++)
                sz[find(i)]++;
        }
        int size(int x)
        {
            return sz[find(x)];
        }
    } dsu[2];
    
    int n;
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin >> n;
        for (int i = 1; i <= n; i++)
            dsu[0].fa[i] = dsu[1].fa[i] = i;
        for (int i = 1; i < n; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            dsu[w].merge(u, v);
        }
    
        int ans = 0;
        dsu[0].solve(n);
        dsu[1].solve(n);
        for (int i = 1; i <= n; i++)
        {
            ans += dsu[0].size(i) * dsu[1].size(i) - 1;
        }
        cout << ans << endl;
    }
    
  • 相关阅读:
    【BZOJ4864】[BeiJing 2017 Wc]神秘物质 Splay
    【BZOJ3438】小M的作物 最小割
    【BZOJ3436】小K的农场 差分约束
    【BZOJ2879】[Noi2012]美食节 动态加边网络流
    【BZOJ1070】[SCOI2007]修车 费用流
    【BZOJ1486】[HNOI2009]最小圈 分数规划
    搜索ABAP程序代码中的字符串
    自定义表的维护
    用户名转换成中文名
    日期计算
  • 原文地址:https://www.cnblogs.com/mollnn/p/14381824.html
Copyright © 2011-2022 走看看