[tarjan][树上最长链]JZOJ 5905 黑暗之魂
分析
因为只有n条边且图连通,所以这是一个环套树(重边和自环特判)
容易联想到这是一个由环贯穿的森林
那么答案可能在森林里的树上最长链里,也有可能要走一段环的路
树上最长链好说,但是走环的路怎么搞呢
我们设f[i]为以i为根的子树内,从i出发的一条最长链的长度
那么再把环上的距离算出来(前缀和,数组为s吧)
则ans=max{f[i]+f[j]+s[i]-s[j] (i>j)
然后我们可以枚举i,用单调队列来维护-s[j]+f[j]即可

#include <iostream> #include <cstdio> #include <deque> #include <stack> #include <algorithm> using namespace std; typedef long long ll; const int N=1e6+10; struct Edge { int u,v,nx; ll w; }g[N*2]; int cnt,list[N]; struct Aedge { int u,v; ll w; bool operator < (const Aedge a) const { return u<a.u||u==a.u&&v<a.v||u==a.u&&v==a.v&&w<a.w; } }a[N]; ll f[N],ans,l[N*2],s[N*2]; int low[N],dfn[N],tme; int lcnt,rcnt,bel[N],root[N]; int cirnum; bool instk[N]; int n; stack<int> stk; void Add(int u,int v,ll w) { g[++cnt].u=u;g[cnt].v=v;g[cnt].w=w;g[cnt].nx=list[u];list[u]=cnt; g[++cnt].u=v;g[cnt].v=u;g[cnt].w=w;g[cnt].nx=list[v];list[v]=cnt; } void Dfs(int u,int fa) { ll max1=0,max2=0; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa&&bel[g[i].v]!=cirnum) { Dfs(g[i].v,u); ll len=f[g[i].v]+g[i].w; if (len>max1) max2=max1,max1=len; else max2=max(max2,len); } ans=max(ans,max1+max2); f[u]=max1; } void Tarjan(int u,int fa) { low[u]=dfn[u]=++tme;stk.push(u);instk[u]=1; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) { if (!dfn[g[i].v]) { Tarjan(g[i].v,u); low[u]=min(low[u],low[g[i].v]); } else if (instk[g[i].v]) low[u]=min(low[u],dfn[g[i].v]); } if (low[u]==dfn[u]) { int o; bool iscir=stk.top()!=u?1:0; lcnt++; do { o=stk.top();stk.pop(); bel[o]=lcnt;instk[o]=0; if (iscir) root[++rcnt]=o,cirnum=lcnt; } while (!stk.empty()&&o!=u); } } int main() { freopen("darksoul.in","r",stdin); freopen("darksoul.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].w); if (a[i].u>a[i].v) swap(a[i].u,a[i].v); } sort(a+1,a+n+1); bool isatree=0; for (int i=1;i<=n;i++) if (a[i].u==a[i].v||a[i].u==a[i-1].u&&a[i].v==a[i-1].v) isatree=1; else Add(a[i].u,a[i].v,a[i].w); if (isatree) { cirnum=-1;Dfs(1,0);printf("%lld",ans+1); return 0; } Tarjan(1,0); for (int i=1;i<=rcnt;i++) Dfs(root[i],0),l[i]=f[root[i]]; for (int i=1;i<=rcnt;i++) for (int j=list[root[i]];j;j=g[j].nx) if (g[j].v==root[i==1?rcnt:i-1]) { s[i]=g[j].w; break; } for (int i=1;i<=rcnt;i++) s[i+rcnt]=s[i],l[i+rcnt]=l[i]; for (int i=1;i<=rcnt*2;i++) s[i]+=s[i-1]; deque<int> q; while (!q.empty()) q.pop_back(); q.push_back(1); for (int i=2;i<=rcnt*2;i++) { while (!q.empty()&&s[i]-s[q.front()]>s[rcnt]/2) q.pop_front(); if (!q.empty()) ans=max(ans,l[i]+l[q.front()]+s[i]-s[q.front()]); while (!q.empty()&&-s[i]+l[i]>=-s[q.back()]+l[q.back()]) q.pop_back(); q.push_back(i); } printf("%lld",ans+1); }
在日渐沉没的世界里,我发现了你。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
· C# 13 中的新增功能实操
· Supergateway:MCP服务器的远程调试与集成工具