zoukankan      html  css  js  c++  java
  • D

    http://abc049.contest.atcoder.jp/tasks/arc065_b

    一开始做这题的时候,就直接蒙逼了,n是2e5,如果真的要算出每一个节点u能否到达任意一个节点i,这不是floyd吗?复杂度要达到n^3,bitset优化也没用了。然后想了想,肯定不是的,如果有很快的方法能判断出一张图的两个节点是否连通,那floyd就没用了。然后想了一节课,发现还是需要判断是否相连啊,不判断就没得玩了。

    然后想到了并查集,确实可以很快判断是否相连了。然后我就想那floyd就没啥用了吧。然后看回以前的笔记,原来floyd可以解决单向的,而并查集就不行了。(最短路径都是可以解决单向的)

    还是知识点不够扎实,不知道各种算法之间的差别,所以想题容易想歪。看见单向的,就不能想去并查集那里了。

    然后就是每个节点都在一个集合里面了,集合中任意两个元素都能相连,同样用第二个并查集维护第二种边。然后枚举节点i,算出这个节点在两个并查集中的集合,他们的交集就是贡献。

    然后就TLE了。

    转化一下思路,对于每个点,它的爸爸是固定的,那么,把这个点的贡献加进去它爸爸那里。这样每个点就算一次就够了,

    al[father1, father2]表示这两个爸爸代表的集合的交集是多少。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 2e5 + 20;
    int fa[2][maxn];
    int getFa(int u, int which) {
        if (fa[which][u] == u) return u;
        else return fa[which][u] = getFa(fa[which][u], which);
    }
    void toMerge(int x, int y, int which) {
        x = getFa(x, which);
        y = getFa(y, which);
        fa[which][y] = x;
    }
    map<pair<int, int>, int>al;
    void work() {
        int n, k1, k2;
        scanf("%d%d%d", &n, &k1, &k2);
        for (int i = 1; i <= n; ++i) {
            fa[0][i] = fa[1][i] = i;
        }
        for (int i = 1; i <= k1; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            toMerge(u, v, 0);
        }
        for (int i = 1; i <= k2; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            toMerge(u, v, 1);
        }
        for (int i = 1; i <= n; ++i) {
            al[make_pair(getFa(i, 0), getFa(i, 1))]++;
        }
        for (int i = 1; i <= n; ++i) {
            cout << al[make_pair(getFa(i, 0), getFa(i, 1))] << " ";
        }
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    感觉最后一步的转化很重要,不知道这步就TLE。我该怎么锻炼这方面的思维。

    要想到为什么可以转换,关键是知道,

    我对于每一个点,我只关心这个点所在的集合和那个点所在的集合的交集。

    那么交集的话,找爸爸出来做代表,算出爸爸1和爸爸2的交集,细分一下就是每个点的贡献和。

  • 相关阅读:
    时间复杂度计算(二)
    程序时间复杂度计算(一)
    一个图像算法岗的面试总结
    文本小票的一种无监督聚类方法
    多个C3P0的java举例
    基于投影和众数特点的粘连sku分割
    GLSL 中的光照计算
    openGL 提升渲染性能 之 顶点数组 VBO IBO VAO
    C++ 中的返回值
    游戏中逻辑线程和逻辑线程的并行
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6545631.html
Copyright © 2011-2022 走看看