基环树小结
持续更新ing

图中央的环显而易见,一般的初始化流程有两个
(1)找环
void Get_ring(LL u,LL fa){
visit[u]=++cnt;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v==fa)
continue;
if(visit[v]){
if(visit[v]<visit[u])
continue;
a[++num]=v;
f[v]=true;
for(;v!=u;v=pre[v]){
a[++num]=pre[v];
f[pre[v]]=true;
}
}else{
pre[v]=u;
Get_ring(v,u);
}
}
}
(2)找边
void Get_edge(LL u,LL now){
if(now==num+1)
return;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v!=a[now+1])
continue;
eval[now]=dis[i].d;
Get_edge(v,now+1);
}
}
题目大意:删掉一条边,在保持联通性的基础上求最小直径
既然要保持连通性,就只能考虑在环上删边
先将环中的每个节点子树最大直径求出(不跨过环)
LL Get_d(LL u,LL fa){
LL stmp=0;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v==fa||f[v])
continue;
stmp=MAX(stmp,Get_d(v,u));
LL now=first[v]+dis[i].d;
if(now>first[u]){
second[u]=first[u];
first[u]=now;
}else if(now>second[u])
second[u]=now;
}
stmp=MAX(stmp,first[u]+second[u]);
return stmp;
}
for(LL i=1;i<=num;++i)
mx[i]=Get_d(a[i],0);
以上均为初始化,下面才是难点
易证基环树的直径为 max{ 环上点子树直径与,跨环部分+左右端点直径和 }
利用环的性质又可分为越过1-n与不越过1-n分别计算
LL stmp=0;
for(LL i=1;i<num;++i){
s0[i]=MAX(s0[i-1],stmp+first[a[i]]);
stmp+=eval[i];
}
stmp=0;
for(LL i=num;i>1;--i){
s1[i]=MAX(s1[i+1],stmp+first[a[i]]);
stmp+=eval[i-1];
}
stmp=0;
for(LL i=1;i<=num;++i){
t0[i]=MAX(t0[i-1],MAX(mx[i],stmp+first[a[i]]));
stmp=MAX(stmp,first[a[i]]);
stmp+=eval[i];
}
stmp=0;
for(LL i=num;i>=1;--i){
t1[i]=MAX(t1[i+1],MAX(mx[i],stmp+first[a[i]]));
stmp=MAX(stmp,first[a[i]]);
stmp+=eval[i-1];
}
My complete code:
#include<cstdio>
using namespace std;
typedef long long LL;
const LL maxn=400000;
struct node{
LL to,next,d;
}dis[maxn*2];
LL n,num,cnt,ans;
LL head[maxn],a[maxn],eval[maxn],visit[maxn],pre[maxn],s0[maxn],s1[maxn],t0[maxn],t1[maxn],mx[maxn],first[maxn],second[maxn];
bool f[maxn];
inline void add(LL u,LL v,LL d){
dis[++num]=(node){v,head[u],d}; head[u]=num;
}
inline LL MAX(LL g1,LL g2){
return g1>=g2?g1:g2;
}
inline LL MIN(LL g1,LL g2){
return g1<=g2?g1:g2;
}
void Get_ring(LL u,LL fa){
visit[u]=++cnt;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v==fa)
continue;
if(visit[v]){
if(visit[v]<visit[u])
continue;
a[++num]=v;
f[v]=true;
for(;v!=u;v=pre[v]){
a[++num]=pre[v];
f[pre[v]]=true;
}
}else{
pre[v]=u;
Get_ring(v,u);
}
}
}
void Get_edge(LL u,LL now){
if(now==num+1)
return;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v!=a[now+1])
continue;
eval[now]=dis[i].d;
Get_edge(v,now+1);
}
}
LL Get_d(LL u,LL fa){
LL stmp=0;
for(LL i=head[u];i;i=dis[i].next){
LL v=dis[i].to;
if(v==fa||f[v])
continue;
stmp=MAX(stmp,Get_d(v,u));
LL now=first[v]+dis[i].d;
if(now>first[u]){
second[u]=first[u];
first[u]=now;
}else if(now>second[u])
second[u]=now;
}
stmp=MAX(stmp,first[u]+second[u]);
return stmp;
}
inline void init(){
scanf("%lld",&n);
for(LL i=1;i<=n;++i){
LL u,v,d;
scanf("%lld%lld%lld",&u,&v,&d);
add(u,v,d);
add(v,u,d);
}
}
inline void solve(){
num=0;
Get_ring(1,0);
a[num+1]=a[1];
Get_edge(a[1],1);
for(LL i=1;i<=num;++i)
mx[i]=Get_d(a[i],0);
LL stmp=0;
for(LL i=1;i<num;++i){
s0[i]=MAX(s0[i-1],stmp+first[a[i]]);
stmp+=eval[i];
}
stmp=0;
for(LL i=num;i>1;--i){
s1[i]=MAX(s1[i+1],stmp+first[a[i]]);
stmp+=eval[i-1];
}
stmp=0;
for(LL i=1;i<=num;++i){
t0[i]=MAX(t0[i-1],MAX(mx[i],stmp+first[a[i]]));
stmp=MAX(stmp,first[a[i]]);
stmp+=eval[i];
}
stmp=0;
for(LL i=num;i>=1;--i){
t1[i]=MAX(t1[i+1],MAX(mx[i],stmp+first[a[i]]));
stmp=MAX(stmp,first[a[i]]);
stmp+=eval[i-1];
}
ans=t0[num];
for(LL i=1;i<num;++i)
ans=MIN(ans,MAX(MAX(t0[i],t1[i+1]),s0[i]+s1[i+1]+eval[num]));
}
int main(){
init();
solve();
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号