【Luogu P4381】[IOI2008] Island
链接:
题目大意:
基环树森林直径板子。
代码:
const int N = 2e6 + 10;
int n;
int head[N], tot = 1;
bool loop[N << 1];
int a[N][2], cnt;
int fa[N];
int Find(int x){return fa[x] == x? x: fa[x] = Find(fa[x]);}
struct edge
{
int to, nxt;ll w;
}e[N << 1];
void Add(int u, int v, int w)
{
e[++tot].to = v, e[tot].nxt = head[u], e[tot].w = w, head[u] = tot;
}
int gotofa[N];
void preWork(int u, int fa)
{
for (int i = head[u], v; i; i = e[i].nxt)
{
if ((v = e[i].to) == fa || loop[i]) continue;
gotofa[v] = i ^ 1;
preWork(v, u);
}
return;
}
ll mx[N][2], L, D;
void DP (int u, int fa)
{
for (int i = head[u], v; i; i = e[i].nxt)
{
if ((v = e[i].to) == fa || loop[i]) continue;
DP (v, u);
if (mx[v][0] + e[i].w > mx[u][0])
mx[u][1] = mx[u][0],
mx[u][0] = mx[v][0] + e[i].w;
else if (mx[v][0] + e[i].w > mx[u][1]) mx[u][1] = mx[v][0] + e[i].w;
}
D = max(D, mx[u][1] + mx[u][0]), L = max(L, mx[u][0]);
return;
}
ll A[N << 1], B[N << 1], dep[N];
int len, total, vis[N];
void dfs(int u, int fa)
{
if (!vis[u]) len++;
vis[u] ++;
B[total] = dep[u];
for (int i = head[u], v; i; i = e[i].nxt)
{
if(!loop[i]) continue;
if (i == fa || vis[v = e[i].to] > 1) continue;
A[total + 1] = A[total] + e[i].w;
total++;
dfs(v, i ^ 1);
}
return ;
}
int q[N << 1];
ll Solve(int lt, int rt)
{
preWork(lt, 0);
ll d = 0;
while (rt)
{
loop[gotofa[rt]] = loop[gotofa[rt] ^ 1] = 1;
D = L = 0;
DP (rt, 0);
d = max(d, D);
dep[rt] = L;
rt = e[gotofa[rt]].to;
}
len = 0, total = 1;
dfs(lt, 0);
q[0] = q[1] = 0;
int h = 1, t = 0;
for (int i = 1; i <= total; i++)
{
while (h <= t && q[h] <= i-len) h ++;
d = max(d, B[q[h]] - A[q[h]] + A[i] + B[i]);
while (h <= t && B[q[t]] - A[q[t]] <= B[i] - A[i]) t--;
q[++t] = i;
}
return d;
}
int main ()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
scanf ("%d", &n);
for (int i = 1; i <= n << 1; i++) fa[i] = i;
for (int u = 1; u <= n; u++)
{
int v;ll w;
scanf ("%d%lld", &v, &w);
int U = Find(u), V = Find(v);
Add(u, v, w), Add(v, u, w);
if(U == V) loop[tot] = loop[tot ^ 1] = 1, a[++cnt][0] = u, a[cnt][1] = v;
else fa[U] = V;
}
ll ans = 0;
for (int i = 1; i <= cnt; i++) ans += Solve(a[i][0], a[i][1]);
printf ("%lld", ans);
return 0;
}