• [APIO2018] Duathlon 铁人两项 圆方树,DP


    [APIO2018] Duathlon 铁人两项

    LG传送门

    圆方树+简单DP。

    不会圆方树的话可以看看我的另一篇文章

    考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数。

    看到题面中的一句话:

    考虑到安全因素,选择的路径经过同一个点至多一次。

    换句话说就是简单路径,用(广义)圆方树的基本条件已经满足,可以把问题变到树上:令方点的权值为所在点双的大小,圆点会被算重所以点权为(-1),统计任意两点间的点权和就好了。直接做是(n ^ 2)的,考虑枚举每一个点看会产生多少贡献,对答案的贡献就乘个点权。

    注意图不一定联通。

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #define R register
    #define I inline
    #define B 1000000
    #define L long long
    using namespace std;
    const int N = 200003;
    char buf[B], *p1, *p2;
    I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
    I int rd() {
        R int f = 0;
        R char c = gc();
        while (c < 48 || c > 57)
            c = gc();
        while (c > 47 && c < 58)
            f = f * 10 + (c ^ 48), c = gc();
        return f;
    }
    L ans = 0;
    int s[N], w[N], dfn[N], low[N], vis[N], sta[N], siz[N], n, tim, cnt, stp, tot;
    vector <int> g[N], G[N];
    I int min(int x, int y) { return x < y ? x : y; }
    void dfs(int x) {
        dfn[x] = low[x] = ++tim, sta[++stp] = x, w[x] = -1, ++tot;
        for (R int i = 0, y, z; i < s[x]; ++i)
            if (!dfn[y = g[x][i]]){
                dfs(y), low[x] = min(low[x], low[y]);
                if (low[y] >= dfn[x]) {
                    w[++cnt] = 1, G[x].push_back(cnt), G[cnt].push_back(x);
                    do {
                        z = sta[stp--], ++w[cnt], G[z].push_back(cnt), G[cnt].push_back(z);
                    } while (z ^ y);
                }
            }
            else
                low[x] = min(low[x], dfn[y]);
    }
    void calc(int x, int f) {
        siz[x] = vis[x] = x <= n;
        L tmp = 0;
        for (R int i = 0, y, S = G[x].size(); i < S; ++i)
            if ((y = G[x][i]) ^ f)
                calc(y, x), tmp += 2ll * siz[y] * siz[x], siz[x] += siz[y];
        tmp += 2ll * siz[x] * (tot - siz[x]), ans += tmp * w[x];
    }
    int main() {
        freopen("a.in", "r", stdin);
        R int m, i, x, y;
        cnt = n = rd(), m = rd();
        for (i = 1; i <= m; ++i)
            x = rd(), y = rd(), g[x].push_back(y), g[y].push_back(x);
        for (i = 1; i <= n; ++i)
            s[i] = g[i].size();
        for (i = 1; i <= n; ++i)
            if (!vis[i])
                stp = 0, tot = 0, dfs(i), calc(i, 0);
        printf("%lld", ans);
        return 0;
    }
    
    
  • 相关阅读:
    找工作经验之——面试(百度篇)
    找工作经验之——面试(微软实习篇)
    以下这个案例给我们什么启发?
    颈椎病
    柳传志写给部下的一封信,告诉你怎样被提拔
    马云:未来三十年会大动荡
    小米:如何用军事理论做商业
    诸葛亮最聪明,为何赢不了
    在最贵的地方点最便宜的菜
    改革有哪四大阻力
  • 原文地址:https://www.cnblogs.com/cj-chd/p/10290837.html
Copyright © 2020-2023  润新知