(这个才是标准的 点双的 广义园方树的写法)
转化太妙了
把方点权值设为点双大小
其余为-1
那么我们就转化为每两个圆点之间的距离和
非常巧妙
(粉兔圆方树讲的太细了
#include
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
#define fi first
#define se second
#define pb push_back
#define inf 1ll<<62
#define endl "\n"
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define de_bug(x) cerr << #x << "=" << x << endl
#define all(a) a.begin(),a.end()
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fer(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int n, m , k;
int dfn[N], low[N];
stack<int>s;
int idx;
int cnt;
vi g[N];
int num ;
int vis[N];
int sz[N];
int d[N];
int ans;
vi e[N];
void tarjan (int x, int fa) {
low[x] = dfn[x] = ++idx;
s.push(x);
++num;
for(auto v : g[x]) {
if(!dfn[v]) {
tarjan(v, x);
low[x] = min(low[x], low[v]);
if(low[v] >= dfn[x]) {
int t;
++cnt;
d[cnt] = 0;
while(1) {
t = s.top();
s.pop();
e[cnt].push_back(t);
e[t].push_back(cnt);
++d[cnt];
if(t == v)break;
}
e[cnt].push_back(x);
e[x].push_back(cnt);
++d[cnt];
}
} else if(v != fa) low[x] = min(low[x], dfn[v]);
}
}
void dfs(int u, int fa) {
if(u <= n)sz[u] = 1;
for(auto v : e[u]) {
if(v == fa)continue;
dfs(v, u);
ans += 2ll * d[u] * sz[u] * sz[v];
sz[u] += sz[v];
}
ans += 2ll * d[u] * sz[u] * (num - sz[u]);
}
void solve() {
cin >> n >> m;
fer(i, 1, n)d[i] = -1;
cnt = n;
fer(i, 1, m) {
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
fer(i, 1, n) {
if(!dfn[i]) {
num = 0;
tarjan(i, 0);
s.pop();
dfs(i, 0);
}
}
cout << ans << endl;
}
signed main() {
IOS;
int _ = 1;
//cin>>_;
while( _-- )
solve();
}