基环树的直径
作者:互联网
转载自LIOI_TEos的题解
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 100; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, v[maxn], v2[maxn], r[maxn]; ll anss, st, ans2, ans3, cnt, dp[maxn<<1], s[maxn];//不知道题解上s数组为什么不开*2 ll ans, d[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int next, to; ll w; }a[maxn<<1]; int head[maxn], len; void add(int x, int y, ll w) { a[++len].to = y; a[len].next = head[x]; a[len].w = w; head[x] = len; } bool dfs(int now, int la) { if(v[now] == 1) { v[now] = 2; r[++cnt] = now; v2[now] = 1; return 1; } v[now] = 1; for(int i=head[now]; i; i=a[i].next) { if(i!=((la-1)^1)+1 && dfs(a[i].to, i)) { if(v[now]!=2) { r[++cnt] = now; v2[now] = 1; s[cnt] = s[cnt-1]+a[i].w; } else { s[st-1] = s[st]-a[i].w;//s[0] //需要这样来得到一个正确的值是因为上一次倍长后没有清空 return 0; } return 1; } } return 0; } void tree_dp(int now) { v2[now] = 1; for(int i=head[now]; i; i=a[i].next) { int y = a[i].to; if(v2[y]) continue; tree_dp(y); ans = max(ans, d[now]+d[y]+a[i].w);//以now为轴连接两条链 d[now] = max(d[now], d[y]+a[i].w);//now的对于它的下一个儿子的其它子节点连接的最长链 } } ll brt(int root) { st = cnt+1, ans2 = 0, ans3 = 0; dfs(root, 0); for(int i=st; i<=cnt; i++) { ans = 0; tree_dp(r[i]);//以环上的每个点为根求树的直径 ans2 = max(ans2, ans); //长度是cnt-(st-1) dp[i+cnt-st+1] = dp[i] = d[r[i]]; s[i+cnt-st+1] = s[i+cnt-st]+s[i]-s[i-1];//s[i-1]就是s[0]的用途? } deque<int> q; for(int i=st; i<=2*cnt-st+1; i++)//i的终点好奇怪? //哦,虽然很绕,但它是对的,cnt+cnt-(st-1)第一个cnt是倍长前的部分的终点,再加上一个长度 { while(q.size() && q.front()<=i-cnt+st-1) { q.pop_front(); } if(q.size()) { ans3 = max(ans3, dp[i]+dp[q.front()]+s[i]-s[q.front()]); } while(q.size() && dp[q.back()]-s[q.back()]<=dp[i]-s[i]) { q.pop_back(); } q.push_back(i); } return max(ans2, ans3); } int main() { n = read(); for(int i=1; i<=n; i++) { int y = read(), z = read(); add(i, y, z); add(y, i, z); } for(int i=1; i<=n; i++) { if(!v2[i]) { anss += brt(i); } } printf("%lld\n", anss); return 0; }
标签:ch,const,int,ll,long,基环树,maxn,直径 来源: https://www.cnblogs.com/Catherine2006/p/16548965.html