洛谷傳送門
BZOJ傳送門
題目描述
比特鎮的路網由 條雙向道路連接的 個交叉路口組成。
最近,比特鎮獲得了一場鐵人兩項錦標賽的主辦權。這場比賽共有兩段賽程:選手先完成一段長跑賽程,然後騎自行車完成第二段賽程。
比賽的路線要按照如下方法規劃:
- 先選擇三個兩兩互不相同的路口 和 ,分別作爲比賽的起點、切換點(運動員在長跑到達這個點後,騎自行車前往終點)、終點。
- 選擇一條從 出發,經過 最終到達 的路徑。考慮到安全因素,選擇的路徑經過同一個點至多一次。
在規劃路徑之前,鎮長想請你幫忙計算,總共有多少種不同的選取 和 的方案,使得在第 步中至少能設計出一條滿足要求的路徑。
輸入輸出格式
輸入格式:
第一行包含兩個整數 和 ,分別表示交叉路口和雙向道路的數量。
接下來 行,每行兩個整數 。表示存在一條雙向道路連接交叉路口 。
保證任意兩個交叉路口之間,至多被一條雙向道路直接連接。
輸出格式:
輸出一行,包括一個整數,表示能滿足要求的不同的選取 和 的方案數。
輸入輸出樣例
輸入樣例#1:
4 3
1 2
2 3
3 4
輸出樣例#1:
8
輸入樣例#2:
4 4
1 2
2 3
3 4
4 2
輸出樣例#2:
14
解題分析
顯然縮出點雙後, 確定兩點之間可以選的中間點就是路徑上所有點和點雙的點數之和。
考慮把單獨一條邊也視爲一個點雙, 那麼建出圓方樹, 把方點的權值設爲點雙的大小, 原點的權值設爲, 路徑上可選中間點數恰好就是路徑和, 然後可以轉化爲計算每點的貢獻。
總複雜度。
代碼如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define MX 200500
#define gc getchar()
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, m, top, arr, dcnt, sum, cnt;
int head[MX], val[MX], siz[MX], dfn[MX], low[MX], sta[MX], h[MX];
ll ans;
struct Edge {int to, nex;} edge[MX << 2];
IN void add1(R int from, R int to)
{edge[++cnt] = {to, head[from]}, head[from] = cnt;}
IN void add2(R int from, R int to)
{edge[++cnt] = {to, h[from]}, h[from] = cnt;}
void tarjan(R int now)
{
dfn[now] = low[now] = ++dcnt;
sta[++top] = now; val[now] = -1; ++sum;
for (R int i = head[now]; i; i = edge[i].nex)
{
if (!dfn[edge[i].to])
{
tarjan(edge[i].to);
low[now] = min(low[now], low[edge[i].to]);
if (low[edge[i].to] == dfn[now])
{
add2(now, ++arr); val[arr] = 1; int tp = 0;
do
{
tp = sta[top--]; add2(arr, tp);
++val[arr];
} while (tp ^ edge[i].to);
}
}
else low[now] = min(low[now], dfn[edge[i].to]);
}
}
void solve(R int now)
{
if (now <= n) siz[now] = 1;
for (R int i = h[now]; i; i = edge[i].nex)
{
solve(edge[i].to);
ans += 1ll * siz[now] * siz[edge[i].to] * val[now];
siz[now] += siz[edge[i].to];
}
ans += 1ll * (sum - siz[now]) * siz[now] * val[now];
}
int main(void)
{
int a, b; in(n), in(m); arr = n;
for (R int i = 1; i <= m; ++i)
{
in(a), in(b);
add1(a, b), add1(b, a);
}
for (R int i = 1; i <= n; ++i)
if (!dfn[i]) sum = 0, tarjan(i), solve(i);
printf("%lld\n", ans * 2);
}