題解-CodeForces835F Roads in the Kingdom
Problem
CodeForces-835F
題意:求基環樹刪去環上任意一邊後直徑最小值,直徑定義為所有點對最近距離的最大值
Solution
首先明確刪去環上一點是不會影響樹內直徑的,所以應當先把所有樹的直徑求出來,這是樹形Dp可以解決的,同時建議使用樹形Dp,可以一次性求出接下來要用到的數據
這是直徑在樹上的情況,接下來考慮直徑從樹開始,中途經過環,最後回到樹的情況
我們先把每個點向樹裏頭能走的最遠距離(也就是帶權深度)\(f[x]\)求出來,同時把環排成一行,放到棧裏頭\(st[1]\)~\(st[top]\),同時把這個環邊權的前綴和求出來,放到數組\(pre\)裏面
考慮刪去邊\((st[d],st[d+1])\)
則最遠點對\((x,y)\)有這兩種情況:
- \(case~1~(1\leq x\leq y\leq d~or~d+1\leq x\leq y\leq n): ans=f[x]-pre[x]+f[y]+pre[y]\)
- \(case~2~(1\leq x\leq d,d+1\leq y\leq n): ans=f[x]+pre[x]+f[y]-pre[y]+pre[n]\)
由於我們需要快速求出刪去每一條邊的最遠點對,所以可以考慮維護前綴後綴最大值:
\(gl_x=\max\{f_i-pre_i\big|i\in[1,x]\}\)
\(gr_x=\max\{f_i-pre_i\big|i\in[x,n]\}\)
\(hl_x=\max\{f_i+pre_i\big|i\in[1,x]\}\)
\(hr_x=\max\{f_i+pre_i\big|i\in[x,n]\}\)
這樣的話,最遠距離\(ans\)可以轉化為\(ans=\max(fl_d+hl_d,fr_{d+1}+hr_{d+1},pre_n-hl_d+gr_{d+1})\)
由於這是個環,記得特殊考慮刪去邊\((top,1)\)
還有一點需要註意,就是加起來的兩個值不能在同一個地方取到,比如說\(fl_2=f_1-pre_1,hl_2=f_1+pre_1\),則\(fl_2\)和\(hl_2\)加起來是沒有意義的,需要舍去,所以我們對於每個數組還需要維護一個次大值
(⊙v⊙)嗯,你沒看錯,就是八個數組
Code
如果需要解釋的話,\(get\_cir\)是找環的,\(dfs\)是處理樹的情況的,\(work\)是處理環的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
template <typename _Tp> inline _Tp read(_Tp&x){
char c11=getchar(),ob=0;x=0;
while(c11^‘-‘&&!isdigit(c11))c11=getchar();if(c11==‘-‘)ob=1,c11=getchar();
while(isdigit(c11))x=x*10+c11-‘0‘,c11=getchar();if(ob)x=-x;return x;
}
const int N=201000;const ll inf=0x3f3f3f3f3f3f3f3f;
struct Edge{int v,nxt,w;}a[N<<1];
int head[N],is[N],st[N],vis[N];
ll f[N],pre[N];
int gl[N],gr[N],hl[N],hr[N],hhl[N],hhr[N],ggl[N],ggr[N];
int n,m,_,top;ll Ans;
void get_cir(int x,int las){
if(vis[x]){
int p=top;
while(st[p]^x)--p;
for(rg int i=p;i<=top;++i)
is[st[i-p+1]=st[i]]=1;
st[0]=-1;top-=p-1;
return ;
}vis[st[++top]=x]=1;
for(int i=head[x];i&&~st[0];i=a[i].nxt)
if(a[i].v^las)get_cir(a[i].v,x);
if(~st[0])vis[st[top--]]=0;
}
void dfs(int x,int las){
ll sec=0ll;
for(int i=head[x];i;i=a[i].nxt)
if(!is[a[i].v]&&a[i].v^las){
dfs(a[i].v,x);f[a[i].v]+=a[i].w;
if(f[a[i].v]>=f[x])sec=f[x],f[x]=f[a[i].v];
else if(f[a[i].v]>sec)sec=f[a[i].v];
}
Ans=max(Ans,f[x]+sec);
}
inline ll G(int x){return x?f[st[x]]-pre[x]:-inf;}
inline ll H(int x){return x?f[st[x]]+pre[x]:-inf;}
void work(){
st[0]=st[top];
for(rg int x=1;x<=top;++x){
for(rg int i=head[st[x-1]];i;i=a[i].nxt)
if(a[i].v==st[x]){
pre[x]=pre[x-1]+a[i].w;
break;
}
dfs(st[x],0);
}
for(rg int i=1;i<=top;++i){
gl[i]=gl[i-1],ggl[i]=ggl[i-1];
hl[i]=hl[i-1],hhl[i]=hhl[i-1];
if(G(i)>G(gl[i]))ggl[i]=gl[i],gl[i]=i;
else if(G(i)>G(ggl[i]))ggl[i]=i;
if(H(i)>H(hl[i]))hhl[i]=hl[i],hl[i]=i;
else if(H(i)>H(hhl[i]))hhl[i]=i;
}
for(rg int i=top;i;--i){
gr[i]=gr[i+1],ggr[i]=ggr[i+1];
hr[i]=hr[i+1],hhr[i]=hhr[i+1];
if(G(i)>G(gr[i]))ggr[i]=gr[i],gr[i]=i;
else if(G(i)>G(ggr[i]))ggr[i]=i;
if(H(i)>H(hr[i]))hhr[i]=hr[i],hr[i]=i;
else if(H(i)>H(hhr[i]))hhr[i]=i;
}
ll ans;
if(hl[top]!=gl[top])ans=G(gl[top])+H(hl[top]);
else ans=max(G(ggl[top])+H(hl[top]),G(gl[top])+H(hhl[top]));
for(rg int i=1;i<top;++i){
ll val=pre[top]+H(hl[i])+G(gr[i+1]);
ll tmp;
if(gl[i]^hl[i])tmp=G(gl[i])+H(hl[i]);
else tmp=max(G(ggl[i])+H(hl[i]),G(gl[i])+H(hhl[i]));
val=max(val,tmp);++i;
if(gr[i]^hr[i])tmp=G(gr[i])+H(hr[i]);
else tmp=max(G(ggr[i])+H(hr[i]),G(gr[i])+H(hhr[i]));
val=max(val,tmp);--i;
ans=min(ans,val);
}cout<<max(ans,Ans)<<endl;
}
void init();void work();
int main(){init();work();return 0;}
void init(){
read(n);int u,v,w;
for(rg int i=1;i<=n;++i){
read(u),read(v),read(w);
a[++_].v=v,a[_].w=w,a[_].nxt=head[u],head[u]=_;
a[++_].v=u,a[_].w=w,a[_].nxt=head[v],head[v]=_;
}get_cir(1,1);
}
題解-CodeForces835F Roads in the Kingdom