题目描述
在Byteotia有n个城镇。 一些城镇之间由无向边连接。 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些)。每两个城镇之间至多只有一条直接连接的道路。人们可以从任意一个城镇直接或间接到达另一个城镇。 每个城镇都有一个公民,他们被孤独所困扰。事实证明,每个公民都想拜访其他所有公民一次(在主人所在的城镇)。所以,一共会有n*(n-1)次拜访。
不幸的是,一个程序员总罢工正在进行中,那些程序员迫切要求购买某个软件。
作为抗议行动,程序员们计划封锁一些城镇,阻止人们进入,离开或者路过那里。
正如我们所说,他们正在讨论选择哪些城镇会导致最严重的后果。
编写一个程序:
读入Byteotia的道路系统,对于每个被决定的城镇,如果它被封锁,有多少访问不会发生,输出结果。
题意
在一张无向图中,原图保证连通,求去除某点后,不能互通的点对,3/4与4/3是不同的点对。
思路
有规律如果去除的不是割点,答案为2*(n-1),如果是割点,则是各个子集大小乘以剩余集合的大小,再求和,加上n-1
所以重点是记录各个子集的大小,因为与生成树不一样,这里有回路,所以应该用两个参数记录,cnt、sum,sum记录子集和,包括回路在内,而cnt是记录满足割点分割的各子集的大小和。tt则是各个子集大小,当前子集满足割点时,进行累加计算。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
#define maxm 1000005
#define inf 1e9
#define IOS ios::sync_with_stdio(false)
#define ll long long
int head[maxn], next[maxm], tov[maxm], num;
void add(int from, int to)
{
next[++num] = head[from];
tov[num] = to;
head[from] = num;
}
ll n, m;
int ind, dfn[maxn], low[maxn];
ll ans[maxn];
ll targan(int cur, int fa)//cur是当前节点,fa是他的父亲
{
int rc = 0;
ll cnt = 1;
ll sum = 1;
int child;
dfn[cur] = ++ind;//计算当前节点的时间戳
low[cur] = dfn[cur];//当前可以访问到的最早时间戳肯定是自己的时间戳
for (int i = head[cur]; i != -1; i = next[i]) //遍历cur的所有出点
{
child = tov[i];
if (dfn[child] && child != fa)
low[cur] = min(low[cur], dfn[child]);//如果访问到了不是父亲节点的节点,更新low的值
if (!dfn[child])//如果这个节点之前没有被访问过
{
ll tt = targan(child, cur);//进行一次dfs过程
if ((dfn[cur] <= low[child] && cur != fa) || rc >= 1)
{
ans[cur] += tt * (n - tt);
cnt += tt;
}
sum += tt;
if (cur == fa)
rc++;
low[cur] = min(low[cur], low[child]);//更新low的值
}
}
//printf(" =%d %d\n",cur,cnt);
if (!ans[cur])
ans[cur] = 2 * (n - 1);
else
ans[cur] += (n - 1 + (n - cnt)*cnt);
return sum;
}
int main()
{
IOS;
cin >> n >> m;
memset(head, -1, sizeof head);
for (int i = 0; i<m; i++)
{
int x, y;
cin >> x >> y;
add(x, y);
add(y, x);
}
targan(1, 1);
for (int i = 1; i <= n; i++)
cout << ans[i] << "\n";
return 0;
}