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;
    }
    
  • 相关阅读:
    Spark 之 内存模型
    Python 之 windows上安装和pycharm 使用
    Kafka之 kafka消费->SparkStreaming|写入->Kafka|kafka消费->hbase
    SparkStreaming之 任务失败后,自动重启
    微信小程序常用赋值方法小结
    eclipse中xml文件Ctrl+左键不跳转解决办法
    SpringCloud简介以及相关组件
    spring怎么设置定时任务
    Http协议请求的不同类型
    Spring各个jar包作用
  • 原文地址:https://www.cnblogs.com/mollnn/p/14381824.html
Copyright © 2011-2022 走看看