cf1000 E. We Need More Bosses
题意:
在无向图中找两个点 \(x,y\),\(x\to y\) 必须经过的边最多
思路:
无向图 双连通分量 缩点
然后变成一棵树,求树的直径
const signed N = 3 + 3e5, M = N*2;
int n, m;
int h[N], e[M], ne[M], tot;
void add(int x, int y) {
e[tot] = y, ne[tot] = h[x], h[x] = tot++;
}
//找桥
int dfn[N], low[N], num; bool bridge[M];
void tarjan(int x, int from) {
dfn[x] = low[x] = ++num;
for(int i = h[x]; ~i; i = ne[i]) {
int y = e[i];
if(!dfn[y]) {
tarjan(y, i), low[x] = min(low[x], low[y]);
if(low[y] > dfn[x]) bridge[i] = bridge[i^1] = 1;
}
else if(i != (from ^ 1)) //注意括号
low[x] = min(low[x], dfn[y]);
}
}
//找连通块
int c[N], dcc;
void dfs(int x) {
c[x] = dcc;
for(int i = h[x]; ~i; i = ne[i]) {
int y = e[i];
if(c[y] || bridge[i]) continue;
dfs(y);
}
}
//缩点
int hc[N], ec[M], nec[M], tc;
void add_c(int x, int y) {
ec[tc] = y, nec[tc] = hc[x], hc[x] = tc++;
}
//直径
int d[N], vis[N], ans;
void dp(int x) {
vis[x] = 1;
for(int i = hc[x]; ~i; i = nec[i]) {
int y = ec[i];
if(vis[y]) continue; dp(y);
ans = max(ans, d[x] + d[y] + 1);
d[x] = max(d[x], d[y] + 1);
}
}
void sol() {
memset(h, -1, sizeof h), memset(hc, -1, sizeof hc);
cin >> n >> m;
while(m--) {
int x, y; cin >> x >> y;
add(x, y), add(y, x);
}
//找桥
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i, 0);
//每个点属于的连通块编号
for(int i = 1; i <= n; i++)
if(!c[i]) ++dcc, dfs(i);
//缩点
tc = 1;
for(int i = 0; i < tot; i++) {
int x = e[i^1], y = e[i];
if(c[x] == c[y]) continue;
add_c(c[x], c[y]);
}
//求直径
dp(1);
cout << ans;
}

浙公网安备 33010602011771号