【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;
}

posted @ 2021-11-16 11:46  Jayun  阅读(17)  评论(0编辑  收藏  举报