Counting Stars hdu - 6184

\(idea\)

假设每条边包含在\(t\)个三元环中,那么这条边的贡献就是$t * (t - 1) / 2 $。将点分为两类 :

  • 度数\(deg \le sqrt(m)\)的点归为第一类点,然后枚举点数,\(O(msqrt(m))\)
  • 度数\(deg > sqrt(m)\)的点归为第二类点,然后枚举边数,\(O(msqrt(m))\)

因为度数超过\(sqrt(m)\)的点至多有\(sqrt(m)\)级别个,比如完全图\(m = \frac{n*(n - 1)}{2}\)。其实复杂度我也没分析得很清楚 orz

\(code\)

需要快速判读两点之间是否连有一条边。就哈希一条边,加到set里面。

const int N = 100005;

int n, m;
int deg[N], pa[N];

bool use[N];

set<LL> s;
vector<int> G[N];

int main()
{
    while(scanf("%d %d", &n, &m) != EOF) {
        mem(pa, 0);
        mem(deg, 0);
        mem(use, 0);

        s.clear();
        Rep(i, 1, n) G[i].clear();

        Rep(i, 1, m) {
            int u, v;
            sc(u), sc(v);
            deg[u]++;
            deg[v]++;

            G[u].pb(v);
            G[v].pb(u);

            s.insert(1ll * u * n + v);
            s.insert(1ll * v * n + u);
        }

        int limit = sqrt(1.0 * m);

        LL ans = 0;
        Rep(i, 1, n) {
            use[i] = 1;
            for (auto v : G[i]) pa[v] = i;
            for (auto v : G[i]) if (!use[v]) {
                LL t = 0;
                if (deg[v] <= limit) {
                    for (auto vv : G[v]) if (pa[vv] == i) t++;
                }
                else {
                    for (auto vv : G[i]) if (s.find(1ll * vv * n + v) != s.end()) t++;
                }
                ans += (t * (t - 1) / 2);
            }
        }

        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2018-10-18 14:22  天之道,利而不害  阅读(193)  评论(0编辑  收藏  举报