APIO 2018 铁人两项 #LOJ2587 圆方树

版权声明:_ https://blog.csdn.net/lunch__/article/details/81837308

学了圆方树后做的第二个题…
感觉圆方树的精髓就是在魔改方点上面啊…

这个题我们首先构建出一颗圆方树
把方点权值设为整个点双的点数
但是圆点存在的基础上可能会多算
所以我们把圆点权值赋为 1 直接统计路径数就好了
算答案的时候如果是圆点就考虑经过它包括它作为起点的路径
方点就不考虑它作为起点只考虑穿过它的路径即可

Codes

#include<bits/stdc++.h>

#define int long long
#define pb push_back

using namespace std;

int read() {
    int _ = 0, ___ = 1; char __ = getchar();
    for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
    for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return ___ * _;
}

const int N = 2e5 + 10, M = 4e5 + 10;
int to[M], head[N], nxt[M], e;
vector<int> kuai[N], G[N];
int n, m, color, val[N], ans;
int size[N], vis[N], all;

void add(int x, int y) {
    to[++ e] = y; nxt[e] = head[x]; head[x] = e;
}

namespace Tarjan {
    int dfn[N], low[N], cnt, Sta[N], top;
    void dfs(int x, int fa) {
        dfn[x] = low[x] = ++ cnt; Sta[++ top] = x;
        for(int j = 0, sz = G[x].size(); j < sz; ++ j) {
            if(!dfn[G[x][j]]) {
                dfs(G[x][j], x);
                low[x] = min(low[x], low[G[x][j]]);
                if(low[G[x][j]] >= dfn[x]) {
                    ++ color;
                    do {
                        kuai[color].pb(Sta[top]);
                    }while(G[x][j] != Sta[top --]);
                    kuai[color].pb(x);
                }
            }
            else if(G[x][j] != fa)
                low[x] = min(low[x], dfn[G[x][j]]);
        }
    }
}

void dfs(int x) {
    //cerr << x << endl;
    vis[x] = 1; all += (size[x] = (x <= n));
    for(int i = head[x]; i; i = nxt[i])
        if(!vis[to[i]]) {
            dfs(to[i]);
            size[x] += size[to[i]];
        }
}

void cal(int x, int fa) {
    if(x <= n) ans += val[x] * (size[x] * (all - size[x] + 1) - 1) << 1;
    else ans += val[x] * (size[x] * (all - size[x])) << 1;
    //ans += (size[x] - 1) * (all - size[x]) * val[x] * 2;
    //if(fa && x <= n) ans += (all - size[x] - 1) * val[x] * 2;
    for(int i = head[x]; i; i = nxt[i]) 
        if(to[i] != fa) {
            cal(to[i], x);
            if(x > n) ans += (size[x] - size[to[i]]) * size[to[i]] * val[x];
            else ans += (size[x] - size[to[i]] - 1) * size[to[i]] * val[x];;
            //ans += (size[x] - size[to[i]] - 1) * (size[to[i]]) * val[x];
            //if(x <= n) ans += (size[to[i]] - 1) * val[x] * 2;
        }
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("2587.in", "r", stdin);
    freopen("2587.out", "w", stdout);
#endif
    int x, y;
    n = read(), m = read();
    for(int i = 1; i <= m; ++ i) {
        x = read(), y = read();
        G[x].pb(y), G[y].pb(x);
    }   
    for(int i = 1; i <= n; ++ i)
        if(!Tarjan::dfn[i])
            Tarjan::dfs(i, 0);
    memset(val, -1, sizeof val);
    for(int i = 1; i <= color; ++ i) { 
        val[i + n] = kuai[i].size();
        for(int j = 0, sz = kuai[i].size(); j < sz; ++ j) {
            //val[i + n] -= (val[kuai[i][j]] = -1);
            val[kuai[i][j]] = -1;
            add(i + n, kuai[i][j]), add(kuai[i][j], i + n);
        }
    }
    for(int i = 1; i <= n; ++ i)
        if(!vis[i]) 
            all = 0, dfs(i), cal(i, 0);
    printf("%lld\n", ans);  
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81837308
今日推荐