记得把 ans 开 long long!!! 记得把 ans 计算过程中的参数强制转化类型 long long!!!
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 4e5 + 10;
//------------------------圆方树------------------------
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
//------------------------圆方树------------------------
vector<int> g[N]; //原图
//------------------------tarjan------------------------
int low[N], dfn[N], tot = 0;
int stk[N], top = 0;
int scc[N], cnt = 0;
//------------------------tarjan------------------------
//------------------------ D P ------------------------
int num = 0;
int sz[N], val[N]; //子树大小&点权
long long ans = 0;
//------------------------ D P ------------------------
void tarjan(int u) { //tarjan并生成圆方树
low[u] = dfn[u] = ++tot;
stk[++top] = u; num++;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u]) {
val[++cnt] = 0;
int x = stk[top];
while (x != u) {
add(x, cnt);
add(cnt, x);
val[cnt]++;
x = stk[--top];
}
add(u, cnt);
add(cnt, u);
val[cnt]++;
}
} else
low[u] = min(low[u], dfn[v]);
}
}
int n, m;
void DP(int u, int father) {
if (u <= n) sz[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == father) continue;
DP(v, u);
ans += (long long) val[u] * sz[u] * sz[v];
sz[u] += sz[v];
}
ans += (long long) val[u] * sz[u] * (num - sz[u]);
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m); cnt = n;
for (int i = 1; i <= n; i++) val[i] = -1; //初始化圆点权值为-1
while (m--) {
int a, b; scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
num = 0;
tarjan(i); top--; //每次tarjan后栈内剩一个点i
DP(i, 0);
}
}
printf("%lld\n", 2ll * ans); //正反路径*2
return 0;
}
记得圆方树会新建方点,所以要把 N 开到 2×105,我直接顺带把 M 也 ×2 了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = 8e5 + 10;
//------------------------圆方树------------------------
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
//------------------------圆方树------------------------
vector<int> g[N]; //原图
//------------------------tarjan------------------------
int low[N], dfn[N], tot = 0;
int stk[N], top = 0;
int scc[N], cnt = 0;
//------------------------tarjan------------------------
//------------------------ D P ------------------------
int num = 0;
int sz[N], val[N]; //子树大小&点权
long long ans = 0;
//------------------------ D P ------------------------
void tarjan(int u) { //tarjan并生成圆方树
low[u] = dfn[u] = ++tot;
stk[++top] = u; num++;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u]) {
val[++cnt] = 0;
int x = stk[top];
while (x != u) {
add(x, cnt);
add(cnt, x);
val[cnt]++;
x = stk[--top];
}
add(u, cnt);
add(cnt, u);
val[cnt]++;
}
} else
low[u] = min(low[u], dfn[v]);
}
}
int n, m;
void DP(int u, int father) {
if (u <= n) sz[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == father) continue;
DP(v, u);
ans += (long long) val[u] * sz[u] * sz[v];
sz[u] += sz[v];
}
ans += (long long) val[u] * sz[u] * (num - sz[u]);
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m); cnt = n;
for (int i = 1; i <= n; i++) val[i] = -1; //初始化圆点权值为-1
while (m--) {
int a, b; scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
num = 0;
tarjan(i); top--; //每次tarjan后栈内剩一个点i
DP(i, 0);
}
}
printf("%lld\n", 2ll * ans); //正反路径*2
return 0;
}
你说得对,但是我**是沙*
tarjan内的“退栈”部分,我写成了x != u…………
正解是x != v
即下面代码 44 行有改动
即可AC
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = 8e5 + 10;
//------------------------圆方树------------------------
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
//------------------------圆方树------------------------
vector<int> g[N]; //原图
//------------------------tarjan------------------------
int low[N], dfn[N], tot = 0;
int stk[N], top = 0;
int scc[N], cnt = 0;
//------------------------tarjan------------------------
//------------------------ D P ------------------------
int num = 0;
int sz[N], val[N]; //子树大小&点权
long long ans = 0;
//------------------------ D P ------------------------
void tarjan(int u) { //tarjan并生成圆方树
low[u] = dfn[u] = ++tot;
stk[++top] = u; num++;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u]) {
val[++cnt] = 0;
for (int x = 0; x != v; top--) {
x = stk[top];
add(x, cnt);
add(cnt, x);
val[cnt]++;
}
add(u, cnt);
add(cnt, u);
val[cnt]++;
}
} else
low[u] = min(low[u], dfn[v]);
}
}
int n, m;
void DP(int u, int father) {
if (u <= n) sz[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == father) continue;
DP(v, u);
ans += (long long) val[u] * sz[u] * sz[v];
sz[u] += sz[v];
}
ans += (long long) val[u] * sz[u] * (num - sz[u]);
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m); cnt = n;
for (int i = 1; i <= n; i++) val[i] = -1; //初始化圆点权值为-1
while (m--) {
int a, b; scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
num = 0;
tarjan(i); top--; //每次tarjan后栈内剩一个点i
DP(i, 0);
}
}
printf("%lld\n", 2ll * ans); //正反路径*2
return 0;
}