D29 基环树 P1399 [NOI2013] 快餐店

视频链接:https://www.bilibili.com/video/BV1wN4y1T7S3/

// Luogu P1399 [NOI2013] 快餐店
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100000+10;
int n;
struct edge{int v,w,ne;}e[N<<1];
int h[N],idx;
int vis[N],fa[N],w[N];
int inc[N],cv[N],cw[N],cn;
double d[N],A[N],B[N],C[N],D[N];
double ans1,ans2=1e18;

void add(int a,int b,int c){
    e[++idx]={b,c,h[a]};h[a]=idx;
}
bool find(int u){
    vis[u]=true;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(v!=fa[u]){
            fa[v]=u; w[v]=e[i].w;      
            if(!vis[v]){//v尚未访问
                if(find(v))return 1;
            }
            else{//v已访问
                int p=u;
                while(1){
                    inc[p]=1;cv[++cn]=p;
                    cw[cn]=w[p];p=fa[p];
                    if(p==u)break;
                }    
              return 1;
            }
        }
    }
    return 0;
}
void dfs(int u,int fa){
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v, w=e[i].w;
        if(!inc[v]&&v!=fa){
            dfs(v,u);
            ans1=max(ans1,d[u]+d[v]+w);
            d[u]=max(d[u],d[v]+w);
        }
    }
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    add(x,y,z);add(y,x,z);
  }
    find(1);//深搜找环
    for(int i=1;i<=cn;++i)
      dfs(cv[i],0);//深搜求直径ans1
    double sum=0,mx=0;
    for(int i=1;i<=cn;++i){//求前缀
        sum+=cw[i-1];
        A[i]=max(A[i-1],sum+d[cv[i]]);
        B[i]=max(B[i-1],mx+d[cv[i]]+sum);
        mx=max(mx,d[cv[i]]-sum);
    }
    sum=mx=0;
    double cn_1=cw[cn];cw[cn]=0;
    for(int i=cn;i>=1;--i){//求后缀
        sum+=cw[i];
        C[i]=max(C[i+1],sum+d[cv[i]]);
        D[i]=max(D[i+1],mx+d[cv[i]]+sum);
        mx=max(mx,d[cv[i]]-sum);
    }
    double res;
    for(int i=1;i<cn;++i){//拼凑答案
        res=max(max(B[i],D[i+1]),
                A[i]+C[i+1]+cn_1);
        ans2=min(ans2,res);
    }
   ans2=min(ans2,B[cn]);//断最后一条边 printf(
"%.1lf",max(ans1,ans2)/2); return 0; }

 

// Luogu P1399 [NOI2013] 快餐店
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100000+10;
int n;
struct edge{int v,w,ne;}e[N<<1];
int h[N],idx=1;
int vis[N],fa[N],w[N];
int inc[N],cv[N],cw[N],cn;
double d[N],A[N],B[N],C[N],D[N];
double ans1,ans2=1e18;

void add(int a,int b,int c){
    e[++idx]={b,c,h[a]};h[a]=idx;
}
//找环,记录inc[v],cv[cn],cw[cn]
bool find(int u,int in){
    vis[u]=true;
    for(int i=h[u];i;i=e[i].ne){
      if(i==(in^1))continue;
        int v=e[i].v;
        fa[v]=u;
        w[v]=e[i].w;  
        if(!vis[v]){//v尚未访问
            if(find(v,i))return 1;
        }
        else{//v已访问
            int p=u;
            while(1){
                inc[p]=1;
                cv[++cn]=p;
                cw[cn]=w[p];
                p=fa[p];
                if(p==u)break;
            }    
          return 1;
        }
    }
    return 0;
}
// 对环点求最大深度d和最大直径ans1
void dfs(int u,int fa){
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v,w=e[i].w;
        if(!inc[v]&&v!=fa){
            dfs(v,u);
            ans1=max(ans1,d[u]+d[v]+w);        
            d[u]=max(d[u],d[v]+w);
        }
    }
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    add(x,y,z);add(y,x,z);
  }
    find(1,0);//找环
    for(int i=1;i<=cn;++i)
      dfs(cv[i],0);//求子树
    double sum=0,mx=0;
    for(int i=1;i<=cn;++i){//求前缀
        sum+=cw[i-1];
        A[i]=max(A[i-1],sum+d[cv[i]]);
        B[i]=max(B[i-1],mx+d[cv[i]]+sum);
        mx=max(mx,d[cv[i]]-sum);
    }
    sum=mx=0;
    double cn_1=cw[cn];cw[cn]=0;
    for(int i=cn;i>=1;--i){//求后缀
        sum+=cw[i];
        C[i]=max(C[i+1],sum+d[cv[i]]);
        D[i]=max(D[i+1],mx+d[cv[i]]+sum);
        mx=max(mx,d[cv[i]]-sum);
    }
    double res;
    for(int i=1;i<cn;++i){//拼凑答案
        res=max(max(B[i],D[i+1]),
                A[i]+C[i+1]+cn_1);
        ans2=min(ans2,res);
    }
   ans2=min(ans2,B[cn]);//断最后一条边 printf(
"%.1lf",max(ans1,ans2)/2); return 0; }

 

posted @ 2022-07-10 23:35  董晓  阅读(311)  评论(0编辑  收藏  举报