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;
}
posted @ 2018-05-29 21:06  poorpool  阅读(222)  评论(0编辑  收藏  举报