LG P4381 [IOI2008]Island
Description
你准备浏览一个公园,该公园由 $N$ 个岛屿组成,当地管理部门从每个岛屿 $i$ 出发向另外一个岛屿建了一座长度为$L_i$ 的桥,不过桥是可以双向行走的。同时,每对岛屿之间都有一艘专用的往来两岛之间的渡船。相对于乘船而言,你更喜欢步行。你希望经过的桥的总长度尽可能长,但受到以下的限制:
- 可以自行挑选一个岛开始游览。
- 任何一个岛都不能游览一次以上。 无论任何时间,你都可以由当前所在的岛 $S$
去另一个从未到过的岛 $D$。从 $S$ 到 $D$ 有如下方法:
- 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离中。
- 渡船:你可以选择这种方法,仅当没有任何桥和以前使用过的渡船的组合可以由 $S$ 走到 $D$ (当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。
注意,你不必游览所有的岛,也可能无法走完所有的桥。
请你编写一个程序,给定 $N$ 座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的长度之和的最大值。
Solution
求基环森林中每个基环树的直径之和
有两种情况
- 直径在某个树上(不跨越环)
- 直径跨越环
对于第一种情况,树形DP
对于第二种情况,优先队列优化DP
#include<iostream> #include<cstring> #include<cstdio> #include<deque> #include<cmath> using namespace std; long long n,tot,head[1000005],vst[1000005],r[1000005],cnt,st; long long sum[2000005],maxx,dp[2000005],ans,f[2000005]; bool vis[1000005]; struct Edge { long long to,nxt; long long w; }edge[2000005]; inline long long read() { long long w=0,f=1; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return w*f; } bool dfs1(long long k,long long e) { if(vst[k]==1) { vst[k]=2; r[++cnt]=k; vis[k]=true; return true; } vst[k]=1; for(long long i=head[k];i;i=edge[i].nxt) { if(i!=((e-1)^1)+1&&dfs1(edge[i].to,i)) { if(vst[k]==1) { r[++cnt]=k; sum[cnt]=sum[cnt-1]+edge[i].w; vis[k]=true; return true; } sum[st-1]=sum[st]-edge[i].w; return false; } } return false; } void dfs2(long long k,long long f) { vis[k]=true; for(long long i=head[k];i;i=edge[i].nxt) { long long v=edge[i].to; if(!vis[v]) { dfs2(v,k); maxx=max(maxx,dp[k]+dp[v]+edge[i].w); dp[k]=max(dp[k],dp[v]+edge[i].w); } } } int main() { n=read(); for(long long i=1;i<=n;i++) { long long x=read(),y=read(); edge[++tot]=(Edge){x,head[i],y}; head[i]=tot; edge[++tot]=(Edge){i,head[x],y}; head[x]=tot; } for(long long i=1;i<=n;i++) { if(!vis[i]) { st=cnt+1; maxx=-1; dfs1(i,0); for(long long j=st;j<=cnt;j++) { dfs2(r[j],0); } for(long long j=st;j<=cnt;j++) { sum[j+cnt-st+1]=sum[j+cnt-st]+sum[j]-sum[j-1]; f[j]=f[j+cnt-st+1]=dp[r[j]]; } deque<long long>q; for(long long j=st;j<=2*cnt-st+1;j++) { while(q.size()&&q.front()<=j-cnt+st-1) { q.pop_front(); } if(q.size()) { maxx=max(maxx,f[j]+sum[j]+f[q.front()]-sum[q.front()]); } while(q.size()&&f[j]-sum[j]>=f[q.back()]-sum[q.back()]) { q.pop_back(); } q.push_back(j); } ans+=maxx; } } printf("%lld\n",ans); return 0; }