1. 程式人生 > >BZOJ4016: [FJOI2014]最短路徑樹問題

BZOJ4016: [FJOI2014]最短路徑樹問題

%d class put temp else if memset truct amp 修改

4016: [FJOI2014]最短路徑樹問題

Time Limit: 5 Sec Memory Limit: 512 MB
Submit: 1715 Solved: 596
[Submit][Status][Discuss]

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個點的路徑最長為多長,第二個整數表示這樣的不同的最長路徑有多少條。

Sample Input

6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1

Sample Output

3 4

HINT

對於所有數據n<=30000,m<=60000,2<=K<=n。

數據保證最短路徑樹上至少存在一條長度為K的路徑。

2016.12.7新加數據一組by - wyx-150137 思路{   顯然構完樹後直接點分治就可以了。   構樹的話我考場上直接暴力記錄路徑+暴力修改決策(因為樹高期望$log$....)。   本地AC,BZOJMLE一次是什麽鬼。。。。 }
#include<bits/stdc++.h>
#define RG register
#define il inline
#define ll long long
#define db double
#define inf 1000000000
#define N 30010
using namespace std;
struct ed{int nxt,to,c;}E[N*4],e[N*2];
int HEAD[N],TOT,head[N],tot;
void LINK(int u,int v,int c){
  E[TOT].nxt=HEAD[u];E[TOT].to=v;
  E[TOT].c=c;HEAD[u]=TOT++;
}
void link(int u,int v,int c){
  e[tot].nxt=head[u];e[tot].to=v;
  e[tot].c=c;head[u]=tot++;
}
int n,m,D[N];
typedef pair<int,int>pir;
pair<int,int>pre[N];
bool in[N];
queue<int>que;
vector<pir>ee[N];
bool V[N];
void DFS(int u,int faa){
  V[u]=1;
  for(int i=HEAD[u];i!=-1;i=E[i].nxt){
    int v=E[i].to;if(V[v]||v==faa)continue;
    if(D[v]==D[u]+E[i].c){
      link(v,u,E[i].c),link(u,v,E[i].c),DFS(v,u);
    }
  }
}
void spfa(){
  que.push(1);
  for(int i=1;i<=n;++i)D[i]=300000001;
  D[1]=0;
  while(!que.empty()){
    int u=que.front();que.pop();in[u]=0;
    for(int i=HEAD[u];i!=-1;i=E[i].nxt){
      int v=E[i].to;
      if(D[v]>D[u]+E[i].c){
    D[v]=D[u]+E[i].c;
    pre[v]=make_pair(u,E[i].c);
    if(!in[v])que.push(v),in[v]=1;
      }
    }
  }
  DFS(1,1);
}
int f[N],sum,rt,k,sz[N],ans,ans2;bool vis[N];
int tong[N],temp[N];
int sumtong[N],sumtemp[N];
void getrt(int u,int faa){
  f[u]=0,sz[u]=1;
  for(int i=head[u];i!=-1;i=e[i].nxt){
    int v=e[i].to;if(v==faa||vis[v])continue;
    getrt(v,u);f[u]=max(f[u],sz[v]);
    sz[u]+=sz[v];
  }f[u]=max(f[u],sum-sz[u]);
  if(f[u]<f[rt])rt=u;
}
void dfs(int u,int faa,int dep,int d){
  if(dep>k)return;
  if(temp[dep]<d)temp[dep]=d,sumtemp[dep]=1;
  else if(temp[dep]==d)sumtemp[dep]++;
  if(tong[k+1-dep]!=-1){
    if(ans==temp[dep]+tong[k+1-dep]&&d==temp[dep])ans2+=sumtong[k+1-dep];
    else if(ans<temp[dep]+tong[k+1-dep]&&d==temp[dep])ans2=sumtong[k+1-dep]*sumtemp[dep];
    ans=max(temp[dep]+tong[k+1-dep],ans);
  }
  for(int i=head[u];i!=-1;i=e[i].nxt){
    int v=e[i].to;if(v==faa||vis[v])continue;
    dfs(v,u,dep+1,d+e[i].c);
  }
}
void modify(int u,int faa,int dep){
  if(dep>k)return;
  if(tong[dep]<temp[dep])sumtong[dep]=sumtemp[dep];
  else if(tong[dep]==temp[dep])sumtong[dep]+=sumtemp[dep];
  tong[dep]=max(tong[dep],temp[dep]),temp[dep]=sumtemp[dep]=0;
  for(int i=head[u];i!=-1;i=e[i].nxt){
    int v=e[i].to;if(v==faa||vis[v])continue;
    modify(v,u,dep+1);
  }
}
 
void solve(int u){
  vis[u]=1;
  for(int i=2;i<=k+k;++i)tong[i]=temp[i]=-1,sumtemp[i]=sumtong[i]=0;
  tong[1]=0,sumtong[1]=1;
  for(int i=head[u];i!=-1;i=e[i].nxt){
    int v=e[i].to;if(vis[v])continue;
    dfs(v,u,2,e[i].c);
    modify(v,u,2);
  }
  for(int i=head[u];i!=-1;i=e[i].nxt){
    int v=e[i].to;if(vis[v])continue;
    sum=sz[v],rt=0;
    getrt(v,v);
    solve(rt);
  }
}
 
int main(){
  scanf("%d%d%d",&n,&m,&k);
  memset(head,-1,sizeof(head));
  memset(HEAD,-1,sizeof(HEAD));
  for(int i=1;i<=m;++i){
    int u,v,c;scanf("%d%d%d",&u,&v,&c);
    ee[u].push_back(make_pair(v,c));
    ee[v].push_back(make_pair(u,c));
  }
  for(int i=1;i<=n;++i){
    sort(ee[i].begin(),ee[i].end());
    for(int j=ee[i].size()-1;j!=-1;j--)
      LINK(i,ee[i][j].first,ee[i][j].second);
  }
  spfa();
  f[0]=n+1,sum=n;
  getrt(1,1);
  solve(rt);
  printf("%d %d\n",ans,ans2);
  return 0;
}

BZOJ4016: [FJOI2014]最短路徑樹問題