POI 2008, BLO B城市

// 222 POI 2008, BLO.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
/*
http://oj.daimayuan.top/course/23/problem/986

有n个点m条边无向连通图的图,保证没有重边和自环。对于每个点,输出将这个点的所有边删除之后,有多少点对不能互相连通。
这里的点对是有顺序的,也就是(u,v)和(v,u)需要被统计两次。

输入格式
第一行包含两个数n,m(1≤n≤105,1≤m≤5×105)。

接下来m行,每行两个整数u,v表示一条无向边。

输出格式n行,每行一个整数,表示答案。

样例输入
5 5
1 2
2 3
1 3
3 4
4 5
样例输出
8
8
16
14
8
*/
#include <iostream>
#include <cstring>
#include <algorithm>


using namespace std;

const int N = 100010, M = 1000010;
int h[N], e[M], ne[M], idx;
int n, m, root;
int dfn[N], low[N], timestamp;
bool cut[N];
int sz[N];
long long ans[N];

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}


void tarjan(int u) {
	dfn[u] = low[u] = ++timestamp;
	int flag = 0; long long res = 0;
	sz[u] = 1;   long long sum = 0;
	for (int i = h[u]; i != -1; i = ne[i]) {
		int k = e[i];
		if (!dfn[k]) {
			tarjan(k);
			sz[u] += sz[k];
			low[u] = min(low[u], low[k]);
			if (low[k] >= dfn[u]) {
				flag++;  
				res += sum * sz[k]*2;
				sum += sz[k];
				if (u != root || flag > 1) cut[u] = true;
			}
		}
		else {
			low[u] = min(low[u], dfn[k]);
		}
	}

	if (cut[u]) {
		res += 2 * (n - 1);
		res += (n - sum - 1) * (sum) * 2;
	}
	else {
		res = 2 * (n - 1);
	}
	ans[u] = res;
}


int main()
{
	memset(h, -1, sizeof h);
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int a, b; cin >> a >> b;
		add(a, b); add(b, a);
	}

	int root = 1;
	tarjan(root);


	for (int i = 1; i <= n; i++) {
		cout << ans[i] << endl;
	}

	return 0;
}


posted on 2025-08-14 10:01  itdef  阅读(3)  评论(0)    收藏  举报

导航