net core webapi多版本控制與swagger(nswag)配置教程
阿新 • • 發佈:2020-11-04
Solution
因為有 \(n\) 個點和 \(n\) 條邊,所以這就是一個基環樹森林。
那麼題目讓我們求的就是基環樹的直徑之和。
基環樹的直徑只有兩種可能:1.在以環上某一點為根的子樹中 2.在兩顆子樹中並經過環上一部分
那麼分別求出兩種可能的最大值然後比較大小即可。
對於第一種可能,選擇對每一棵樹進行樹形DP,正常求樹的直徑。
同時要記錄下來 \(len\) 陣列,其中 \(len_i\) 表示以環上第 \(i\) 個點為根的子樹中,到根最大的距離。這是為了第二種可能準備。
對於第二種可能,設環為 \(E\) ,我們只要求出 \(\max\limits_{i,j\in E,j<i}\{len_i+len_j+dis_{i,j}\}\)
但是如果列舉 \(i,j\) 的話複雜度是不允許的。我們將環破為鏈,並且複製成兩倍,設 \(sum_{i}\) 表示從 \(1\) 到 \(i\) 的 \(dis\) 的字首和,也就是 \(sum_i=sum_{i-1}+dis_{i-1,i}\) ,那麼上面的式子就成了 \(len_i+len_j+sum_i-sum_j\rightarrow len_i+sum_i+len_j-sum_j\) 。
將 \(i\) 固定,只考慮 \(j\) ,那麼對於兩個點 \(j,k\) , 如果有 \(len_j-sum_j<len_k-sum_k\) ,那麼肯定選擇 \(k\) ,所以用單調佇列優化DP。
Code
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e6+10; ll n,tot,cnt,ans,st,ans1,ans2,ans3; ll head[N]; struct edge{ int to,nxt,w; }e[N<<1]; ll vis1[N],vis2[N],dfn[N],d[N],dp[N<<1],s[N]; inline void add(int u,int v,int w){ e[++tot].to=v; e[tot].w=w; e[tot].nxt=head[u]; head[u]=tot; } bool dfs(int x,int pre){ if(vis1[x]==1){ vis1[x]=2,dfn[++cnt]=x,vis2[x]=1; return 1; } vis1[x]=1; for(int i=head[x];i;i=e[i].nxt) if(i!=((pre-1)^1)+1&&dfs(e[i].to,i)){ if(vis1[x]!=2) dfn[++cnt]=x,vis2[x]=1,s[cnt]=s[cnt-1]+e[i].w; else{ s[st-1]=s[st]-e[i].w; return 0; } return 1; } return 0; } inline void tree_dp(int now){ vis2[now]=1; for(int i=head[now];i;i=e[i].nxt){ int y=e[i].to; if(vis2[y]) continue; tree_dp(y); ans=max(ans,d[now]+d[y]+e[i].w); d[now]=max(d[now],d[y]+e[i].w); } } inline ll query(int rt){ st=cnt+1,ans2=0,ans3=0; dfs(rt,0); for(int i=st;i<=cnt;i++){ ans=0; tree_dp(dfn[i]); ans2=max(ans2,ans); dp[i+cnt-st+1]=dp[i]=d[dfn[i]]; s[i+cnt-st+1]=s[i+cnt-st]+s[i]-s[i-1]; } deque<int> q; for(int i=st;i<=2*cnt-st+1;i++){ 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(){ scanf("%lld",&n); for(int i=1,y,z;i<=n;i++){ scanf("%d%d",&y,&z); add(i,y,z);add(y,i,z); } for(int i=1;i<=n;i++) if(!vis2[i]) ans1+=query(i); printf("%lld\n",ans1); return 0; }