• [NOI2013]快餐店


    先贴个题目连接咯

    P1399 [NOI2013]快餐店 

    首先我们要知道,如果是树的话,重心的位置一定在一半的直径里那个位置对吧。

    所以如果图是一棵树,那么1/2的直径长就是答案了。

    (然而这道题没有树的部分分)

    看到有n条边就知道是基环树。

    既然是基环树,那么我们就应该把环作为重点研究对象。

    环就是解题的关键,习惯性地把基环树画成细菌

    此时这个基环树的直径有两种情况 有经过基环 或 没有经过基环

    没有经过基环的就是环上挂着的每一棵小子树的最大直径了。

    有经过基环的怎么求呢?

    考虑枚举每个位置把环断开(基环树常见套路)。

    对每一个子树求一个最大深度,然后Max(两个子树最大深度加它们在环上的距离)就为直径了。

    但我们有很多种断环方案,每一次都求一次复杂度肯定是要上天的。

    所以想个办法优化(这里借鉴了ljh2000的方法)

    先在1到tot(环长)的地方断开。

    pre[]与bck[]分别表示前缀和后缀的 Max[某个子树最大深度+它的前缀(后缀)链长]

    bs1[]和bs2[]分别表示前缀和后缀的 Max[某两个子树的最大深度+它们之间的距离]

    所以每次从i到i+1的地方断开,答案的求法就很简单了。

    1 For(i,1,tot-1){
    2    mx1=max(bs1[i],bs2[i+1]);
    3    mx2=max(mx1,pre[i]+bck[i+1]+crD[0]);//crD[0]为1与tot之间边的长度
    4    Fn=min(Fn,max(mx1,mx2));
    5 }

    DFS抠环、断环的时候比较繁琐一定要注意细节。

    好了上代码(作为一道黑题,并没有很难,千万不要被标签吓倒)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<cmath>
      7 
      8 #define For(i,a,b) for(register int i=a;i<=b;++i)
      9 #define Dwn(i,a,b) for(register int i=a;i>=b;--i)
     10 #define Pn putchar('
    ')
     11 #define Re register
     12 #define Db double
     13 
     14 using namespace std;
     15 
     16 const int N=1e5+5;
     17 
     18 int head[N],nxt[N*2],v[N*2],cnt=1;
     19 Db w[N*2],dia[N],z,dmx[N],Fn;
     20 int n,m,x,y;
     21 inline void read(int &v){
     22     v=0;
     23     char c=getchar();
     24     while(c<'0'||c>'9')c=getchar();
     25     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
     26 }
     27 inline void read(Db &v){
     28     v=0;
     29     char c=getchar();
     30     while(c<'0'||c>'9')c=getchar();
     31     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
     32 }
     33 void add(int ux,int vx,Db wx){
     34     nxt[++cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx;
     35     nxt[++cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx;
     36 }
     37 
     38 int tot=0,top=0,st[N],cr[N*2],vis[N],suc=0,fc[N];
     39 Db crD[N*2],stD[N];
     40 void dfsCir(int x,int fa){
     41     vis[x]=1;
     42     if(x==1)st[++top]=x,stD[top]=0;
     43     for(Re int i=head[x];i;i=nxt[i]){
     44         int vv=v[i]; if(vv==fa)continue;
     45         if(!vis[vv]){
     46             st[++top]=vv; stD[top]=w[i];
     47             dfsCir(vv,x);
     48         }else{
     49             suc=1;
     50             while(st[top]!=vv){
     51                 fc[st[top]]=1;
     52                 cr[++tot]=st[top];
     53                 crD[tot]=stD[top--];
     54             }
     55             fc[st[top]]=1;
     56             cr[++tot]=st[top];
     57             crD[tot]=w[i];
     58             return;
     59         }
     60         if(suc)return;
     61     }
     62     top--;
     63 }
     64 int pos;
     65 Db mxD;
     66 void dfsTrD(int x,Db dix,int fa){
     67     if(dix>mxD)mxD=dix,pos=x;
     68     for(Re int i=head[x];i;i=nxt[i]){
     69         int vv=v[i];
     70         if(vv==fa||fc[vv])continue;
     71         dfsTrD(vv,dix+w[i],x);
     72     }
     73 }
     74 Db GetTrD(int x){
     75     pos=mxD=0;
     76     dfsTrD(x,0,0);
     77     mxD=0;
     78     dfsTrD(pos,0,0);
     79     return mxD;
     80 }
     81 
     82 Db pre[N],bck[N],bs1[N],bs2[N],Ds=0; 
     83 void DP(){
     84     Ds=mxD=0;
     85      For(i,1,tot){
     86          pre[i]=max(pre[i-1],dmx[cr[i]]+Ds);
     87          if(i>=2)bs1[i]=max(bs1[i-1],mxD+Ds+dmx[cr[i]]);
     88          mxD=max(mxD,dmx[cr[i]]-Ds);
     89          Ds+=crD[i];
     90     }
     91     Ds=mxD=0;
     92     crD[0]=crD[tot];
     93     Dwn(i,tot,1){
     94         bck[i]=max(bck[i+1],dmx[cr[i]]+Ds);
     95         if(i<=tot-1)bs2[i]=max(bs2[i+1],mxD+Ds+dmx[cr[i]]);
     96         mxD=max(mxD,dmx[cr[i]]-Ds);
     97         Ds+=crD[i-1];
     98     }
     99     Fn=bs1[tot];
    100     For(i,1,tot-1){
    101         Db mx1=max(bs1[i],bs2[i+1]);
    102         Db mx2=max(mx1,pre[i]+bck[i+1]+crD[0]);
    103         Fn=min(Fn,max(mx1,mx2));
    104     }
    105 }
    106 
    107 int main(){
    108     //freopen("ex.in","r",stdin);
    109 //    freopen("ex.out","w",stdout);
    110     read(n); 
    111     For(i,1,n){read(x); read(y); read(z); add(x,y,z);}
    112     dfsCir(1,0); 
    113     For(i,1,tot){
    114         fc[cr[i]]=0;
    115         dia[cr[i]]=GetTrD(cr[i]);
    116         fc[cr[i]]=1;
    117     }
    118     For(i,1,tot){
    119         mxD=0; 
    120         dfsTrD(cr[i],0,0);
    121         dmx[cr[i]]=mxD;
    122     } 
    123     DP();
    124     For(i,1,tot)Fn=max(Fn,dia[cr[i]]);
    125     printf("%.1lf",Fn/2.0);
    126     return 0;
    127 }
    128     
  • 相关阅读:
    Android_Studio常用插件
    Android_Studio 及SDK下载
    Ubuntu 16.04 LTS 正式发布:系统将持续更新5年
    Windows通用应用平台
    Jquery局部打印插件
    WEB打印插件Lodop
    WEB打印插件jatoolsPrinter
    hdu1863
    PromiseKit入门
    高速排序
  • 原文地址:https://www.cnblogs.com/HLAUV/p/10629695.html
Copyright © 2020-2023  润新知