1. 程式人生 > 實用技巧 >LG P4381 [IOI2008]Island

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