loj2587 「APIO2018」铁人两项

圆方树orz,参见猫的课件(apio和wc的)以及这里那里

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int n, m, uu, vv, oea[100005], loo[100005], dfn[100005], idx, sta[100005];
int siz[200005], val[200005], tot, sze, din, ont, cnt, hea[200005];
ll ans;
struct Edge{
    int too, nxt;
}odge[400005], edge[400005];
void add_odge(int fro, int too){
    odge[++ont].nxt = oea[fro];
    odge[ont].too = too;
    oea[fro] = ont;
}
void add_edge(int fro, int too){
    edge[++cnt].nxt = hea[fro];
    edge[cnt].too = too;
    hea[fro] = cnt;
}
void tarjan(int x){
    dfn[x] = loo[x] = ++idx;
    sta[++din] = x;
    siz[x] = 1;
    val[x] = -1;
    for(int i=oea[x]; i; i=odge[i].nxt){
        int t=odge[i].too;
        if(!dfn[t]){
            tarjan(t);
            loo[x] = min(loo[x], loo[t]);
            if(loo[t]>=dfn[x]){
                int p;
                tot++;
                add_edge(x, tot);
                do{
                    p = sta[din--];
                    val[tot]++;
                    add_edge(tot, p);
                    siz[tot] += siz[p];
                }while(p!=t);
                val[tot]++; siz[x] += siz[tot];
            }
        }
        else    loo[x] = min(loo[x], dfn[t]);
    }
}
void dfs(int x){
    if(x<=n)    ans += (ll)val[x] * (sze - 1);
    ans += (ll)val[x] * (sze - siz[x]) * siz[x];
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        dfs(t);
        ans += (ll)val[x] * (sze - siz[t]) * siz[t];
    }
}
int main(){
    cin>>n>>m;
    tot = n;
    for(int i=1; i<=m; i++){
        scanf("%d %d", &uu, &vv);
        add_odge(uu, vv);
        add_odge(vv, uu);
    }
    for(int i=1; i<=n; i++)
        if(!dfn[i]){
            tarjan(i);
            sze = siz[i];
            dfs(i);
        }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/poorpool/p/9107926.html
今日推荐