建树+点分治 难度在于建树
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define sc second
#define pr pair<int,int>
#define mp make_pair
using namespace std;
int root,Cnt,F_top,cnt,n,m,K,N,instack[1000005],last[1000005],vis[1000005],dis[1000005],F_[1000005],F[1000005],G[1000005],F_stack[1000005],G_stack[1000005],F_sum[1000005],G_sum[1000005],sz[1000005];
long long ans,ans_sum;
priority_queue<pr,vector<pr>,greater<pr> > q;
struct node{
int to,next,val;
}e[1000005];
void add(int a,int b,int c){
e[++cnt].to=b;
e[cnt].next=last[a];
e[cnt].val=c;
last[a]=cnt;
}
void Dijkstra(int S){
for (int i=1; i<=n; i++) vis[i]=0,dis[i]=1e9;
dis[S]=0;
q.push(mp(0,S));
while (!q.empty()){
int x=q.top().sc;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (dis[V]>dis[x]+e[i].val){
dis[V]=dis[x]+e[i].val;
q.push(mp(dis[V],V));
}
}
}
}
struct node1{
int x,val;
};
vector<node1> vec[1000005];
bool cmp(node1 a,node1 b){
return a.x<b.x;
}
struct node2{
int x,y,val;
}E[1000005];
void dfs(int x){
vis[x]=1;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
vec[x].push_back((node1){V,e[i].val});
}
sort(vec[x].begin(),vec[x].end(),cmp);
for (int i=0; i<(int)vec[x].size(); i++){
int V=vec[x][i].x;
if (dis[V]==dis[x]+vec[x][i].val && !vis[V]) {
E[++Cnt]=(node2){x,V,vec[x][i].val};
dfs(V);
}
}
}
void find_root(int x,int fa){
sz[x]=1,F_[x]=0;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==fa) continue;
find_root(V,x);
sz[x]+=sz[V];
F_[x]=max(F_[x],sz[V]);
}
F_[x]=max(F_[x],N-sz[x]);
if (F_[x]<F_[root]) root=x;
}
void get_dis(int x,int fa,int val,int dep){
if (dep==K){
int ANS=val,ANS_sum=1;
if (ANS==ans) ans_sum+=ANS_sum;
else if (ANS>ans) ans=ANS,ans_sum=ANS_sum;
}
if (!instack[dep]) F_stack[++F_top]=dep,instack[dep]=1;
if (F[dep]==val) F_sum[dep]++;
else if (F[dep]<val) F[dep]=val,F_sum[dep]=1;
sz[x]=1;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==fa) continue;
get_dis(V,x,val+e[i].val,dep+1);
sz[x]+=sz[V];
}
}
void solve(int x){
int G_top=0;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V]) continue;
F_top=0;
get_dis(V,x,e[i].val,2);
for (int j=1; j<=F_top; j++)
if (K+1-F_stack[j]>=1){
int ANS=F[F_stack[j]]+G[K+1-F_stack[j]];
long long ANS_sum=1ll*F_sum[F_stack[j]]*G_sum[K+1-F_stack[j]];
if (ANS==ans) ans_sum+=ANS_sum;
else if (ANS>ans) ans=ANS,ans_sum=ANS_sum;
}
for (int j=1; j<=F_top; j++)
if (F[F_stack[j]]==G[F_stack[j]]) G_sum[F_stack[j]]+=F_sum[F_stack[j]];
else if (F[F_stack[j]]>G[F_stack[j]]) G[F_stack[j]]=F[F_stack[j]],G_sum[F_stack[j]]=F_sum[F_stack[j]];
for (int j=1; j<=F_top; j++) F[F_stack[j]]=0,instack[F_stack[j]]=0,G_stack[++G_top]=F_stack[j];
}
for (int i=1; i<=G_top; i++) G[G_stack[i]]=0;
}
void divide(int x){
vis[x]=1;
solve(x);
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V]) continue;
N=sz[V],root=0;
find_root(V,x);
divide(root);
}
}
int main(){
scanf("%d%d%d",&n,&m,&K);
for (int i=1; i<=m; i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
Dijkstra(1);
memset(vis,0,sizeof(vis));
dfs(1);
F_[0]=1e9;
cnt=0;
memset(last,0,sizeof(last));
for (int i=1; i<=Cnt; i++) add(E[i].x,E[i].y,E[i].val),add(E[i].y,E[i].x,E[i].val);
memset(vis,0,sizeof(vis));
N=n,root=0;
find_root(1,0);
divide(root);
printf("%lld %lld
",ans,ans_sum);
return 0;
}
/*
4 6 2
1 2 5
1 4 2
2 4 6
2 3 6
3 4 5
1 3 1
*/