• 【BZOJ4016】【FJOI2014】最短路径树问题


    题意:

    Description

    给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
    往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
    可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
    这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

    Input

    第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。

    Output

    输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。

    n<=30000,m<=60000,2<=K<=n

    题解:

    一眼题啊。。。SBFA写挂能怪谁QAQ

    先把最小路径树建出来,然后就是点分治经典问题了;

    关于最小路径树:

    先以1为源点跑一边最短路,然后把对最短路没有贡献的边去掉,再按照字典序dfs一次把非树边去掉(有可能有多个最短路)即可。

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #define inf 2147483647
      8 #define eps 1e-9
      9 using namespace std;
     10 typedef long long ll;
     11 struct edge{
     12     int v,w,next; 
     13 }a[200001],_a[200001],__a[200001];
     14 struct _edge{
     15     int u,v,w;
     16     friend bool operator <(_edge a,_edge b){
     17         return a.u==b.u?a.v>b.v:a.u<b.u;
     18     }
     19 }e[200001];
     20 int n,m,k,u,v,w,ans=0,anss,rt,S,tot=0,_tot=0,__tot=0,siz[200001],mx[200001],head[200001],_head[200001],__head[200001],f[200001],g[200001],_f[200001],_g[200001],dis[200001];
     21 bool used[200001],vis[200001];
     22 void add(int u,int v,int w){
     23     a[++tot].v=v;
     24     a[tot].w=w;
     25     a[tot].next=head[u];
     26     head[u]=tot;
     27 }
     28 void _add(int u,int v,int w){
     29     _a[++_tot].v=v;
     30     _a[_tot].w=w;
     31     _a[_tot].next=_head[u];
     32     _head[u]=_tot;
     33 }
     34 void __add(int u,int v,int w){
     35     __a[++__tot].v=v;
     36     __a[__tot].w=w;
     37     __a[__tot].next=__head[u];
     38     __head[u]=__tot;
     39 }
     40 void spfa(){
     41     queue<int>q;
     42     bool isin[200001];
     43     memset(isin,0,sizeof(isin));
     44     q.push(1);
     45     isin[1]=true;
     46     dis[1]=0;
     47     while(!q.empty()){
     48         int u=q.front();
     49         q.pop();
     50         isin[u]=false;
     51         for(int tmp=_head[u];tmp!=-1;tmp=_a[tmp].next){
     52             int v=_a[tmp].v;
     53             if(dis[v]>dis[u]+_a[tmp].w){
     54                 dis[v]=dis[u]+_a[tmp].w;
     55                 if(!isin[v]){
     56                     isin[v]=true;
     57                     q.push(v);
     58                 }
     59             }
     60         }
     61     }
     62     sort(e+1,e+m*2+1);
     63     for(int i=1;i<=m*2;i++){
     64         if(dis[e[i].v]==dis[e[i].u]+e[i].w){
     65             __add(e[i].u,e[i].v,e[i].w);
     66         }
     67     }
     68 }
     69 void build(int u){
     70     used[u]=true;
     71     for(int tmp=__head[u];tmp!=-1;tmp=__a[tmp].next){
     72         int v=__a[tmp].v,w=__a[tmp].w;
     73         if(!used[v]){
     74             //printf("%d %d %d
    ",u,v,w);
     75             add(u,v,w);
     76             add(v,u,w);
     77             build(v);
     78         }
     79     }
     80 }
     81 void dfsrt(int u,int fa){
     82     siz[u]=1;
     83     mx[u]=0;
     84     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     85         int v=a[tmp].v;
     86         if(v!=fa&&!vis[v]){
     87             dfsrt(v,u);
     88             mx[u]=max(mx[u],siz[v]);
     89             siz[u]+=siz[v];
     90         }
     91     }
     92     mx[u]=max(mx[u],S-siz[u]);
     93     if(mx[u]<mx[rt])rt=u;
     94 }
     95 void dfs(int u,int fa,int dpt,int ww){
     96     if(dpt>k)return;
     97     if(ww>_f[dpt]){
     98         _f[dpt]=ww;
     99         _g[dpt]=1;
    100     }else if(ww==_f[dpt]){
    101         _g[dpt]++;
    102     }
    103     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    104         int v=a[tmp].v;
    105         if(v!=fa&&!vis[v]){
    106             dfs(v,u,dpt+1,ww+a[tmp].w);
    107         }
    108     }
    109 }
    110 void divide(int u){
    111     f[0]=0,g[0]=1;
    112     for(int i=1;i<=k;i++)f[i]=g[i]=0;
    113     vis[u]=true;
    114     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    115         int v=a[tmp].v,w=a[tmp].w;
    116         if(!vis[v]){
    117             for(int i=0;i<=k;i++)_f[i]=_g[i]=0;
    118             dfs(v,0,1,w);
    119             for(int i=1;i<=k;i++){
    120                 if(ans<f[k-i]+_f[i]){
    121                     ans=f[k-i]+_f[i];
    122                     anss=g[k-i]*_g[i];
    123                 }else if(ans==f[k-i]+_f[i]){
    124                     anss+=g[k-i]*_g[i];
    125                 }
    126             }
    127             for(int i=1;i<=k;i++){
    128                 if(f[i]<_f[i]){
    129                     f[i]=_f[i];
    130                     g[i]=_g[i];
    131                 }else if(f[i]==_f[i]){
    132                     g[i]+=_g[i];
    133                 }
    134             }
    135         }
    136     }
    137     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    138         int v=a[tmp].v;
    139         if(!vis[v]){
    140             rt=0,S=siz[v];
    141             dfsrt(v,0);
    142             divide(rt);
    143         }
    144     }
    145 }
    146 int main(){
    147     memset(dis,0x3f,sizeof(dis));
    148     memset(head,-1,sizeof(head));
    149     memset(_head,-1,sizeof(_head));
    150     memset(__head,-1,sizeof(__head));
    151     memset(used,0,sizeof(used));
    152     memset(vis,0,sizeof(vis));
    153     scanf("%d%d%d",&n,&m,&k);
    154     k--;
    155     for(int i=1;i<=m;i++){
    156         scanf("%d%d%d",&u,&v,&w);
    157         _add(u,v,w);
    158         _add(v,u,w);
    159         e[i*2-1]=(_edge){u,v,w};
    160         e[i*2]=(_edge){v,u,w};
    161     }
    162     spfa();
    163     build(1);
    164     mx[rt=0]=666666,S=n;
    165     dfsrt(1,0);
    166     divide(rt);
    167     printf("%d %d",ans,anss);
    168     return 0;
    169 }

    PS:BZOJ数据极水,我写了SPFA+没判字典序都过了

  • 相关阅读:
    多种方式实现 Future 回调返回结果
    Google Guava ListeningExecutorService
    MySQL数据库的核心MVCC详解
    共收录 Twitter 的 14 款开源软件,第 1 页
    共收录 微软 的 62 款开源软件,第 1 页
    共收录 腾讯 的 48 款开源软件,第 1 页
    共收录 Netflix 的 22 款开源软件,第 1 页
    什么是yml文件
    共收录 NASA 的 26 款开源软件,第 1 页
    共收录 Github 的 5 款开源软件,第 1 页
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9726323.html
Copyright © 2020-2023  润新知