这道题的思想很好
建出最短路径树然后进行点分
每次用两个数组来记录
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
char c;
inline void read(int &a)
{
a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
struct No
{
int u,v;
int Dis,len;
inline friend bool operator <(No a,No b)
{return a.Dis>b.Dis;}
};
priority_queue<No>Q;
int Dis[1000001];
struct Chain
{
int u,len;
Chain *next;
Chain(){next=NULL;}
}*S[1000001],*Head[1000001];
int F[1000001];
struct Side
{
int u,len;
inline friend bool operator <(Side a,Side b)
{return a.u<b.u;}
};
vector<Side>SS[100001];
inline void Add(int a,int b,Chain **Head,int len)
{
Chain *tp=new Chain;
tp->next=Head[a];
Head[a]=tp;
tp->len=len;
tp->u=b;
}
inline void Replace(int a,int b,Chain **Head,int len)
{
Chain *tp=new Chain;
tp->next=Head[a];
Head[a]=tp;
tp->len=len;
tp->u=b;
}
inline void Dij(Chain **Head,int S)
{
while(!Q.empty())Q.pop();
Q.push((No){S,S,0,0});
No tp;
while(!Q.empty())
{
tp=Q.top();
Q.pop();
if(tp.v!=1&&tp.Dis==Dis[tp.v])
SS[tp.u].push_back((Side){tp.v,tp.len});
else if(Dis[tp.v])continue;
else
{
Dis[tp.v]=tp.Dis;
F[tp.v]=tp.u;
SS[tp.u].push_back((Side){tp.v,tp.len});
//Replace(tp.u,tp.v,SS,tp.len);
for(Chain *t=Head[tp.v];t;t=t->next)
if(t->u!=S&&!Dis[t->u])
Q.push((No){tp.v,t->u,t->len+tp.Dis,t->len});
}
}
}
bool Chosen[100001];
int Heavy[100001];
int size[100001];
int root,Max;
bool done[100001];
void Build(int u)
{
size[u]++;
sort(SS[u].begin(),SS[u].end());
for(int i=0;i<SS[u].size();i++)
if(SS[u][i].u!=u&&!done[SS[u][i].u])
done[SS[u][i].u]=true,Add(u,SS[u][i].u,Head,SS[u][i].len),Add(SS[u][i].u,u,Head,SS[u][i].len),Build(SS[u][i].u),size[u]+=size[SS[u][i].u];
}
void FindRoot(int u,int f)
{
size[u]=1;
Heavy[u]=0;
for(Chain *tp=Head[u];tp;tp=tp->next)
if(!Chosen[tp->u]&&tp->u!=f)
{
FindRoot(tp->u,u);
Heavy[u]=max(Heavy[u],size[tp->u]);
size[u]+=size[tp->u];
}
Heavy[u]=max(Heavy[u],Max-size[u]);
if(Heavy[u]<Heavy[root])
root=u;
}
int tot;
int L[100001];
struct R
{
int key,f;
inline friend bool operator <(R a,R b)
{return a.key>b.key;}
inline friend bool operator ==(R a,R b)
{return a.f==b.f;}
}LP[1000001];
int Op2[1000001][2];
int Op[1000001][2];
const
int INF=1<<29;
int K;
void DFS(int x,int dep,int len,int fa)
{
if(dep>=K)return ;
if(Op2[dep][0]<len)
Op2[dep][0]=len,Op2[dep][1]=1;
else if(Op2[dep][0]==len)
Op2[dep][1]++;
for(Chain *tp=Head[x];tp;tp=tp->next)
if(tp->u!=fa&&!Chosen[tp->u])
DFS(tp->u,dep+1,len+tp->len,x);
}
int longest,Kind;
void Divid(int u)
{
int i,j;
Op[0][0]=0;
Op[0][1]=1;
for(Chain*tp=Head[u];tp;tp=tp->next)
if(!Chosen[tp->u])
{
DFS(tp->u,1,tp->len,u);
for(i=1;Op2[i][1];i++)
if(longest<Op2[i][0]+Op[K-i-1][0])
longest=Op2[i][0]+Op[K-i-1][0],Kind=Op2[i][1]*Op[K-i-1][1];
else if(longest==Op2[i][0]+Op[K-i-1][0])Kind+=Op2[i][1]*Op[K-i-1][1];
for(i=1;Op2[i][1];i++)
if(Op2[i][0]>Op[i][0])
Op[i][0]=Op2[i][0],Op[i][1]=Op2[i][1];
else if(Op[i][0]==Op2[i][0])Op[i][1]+=Op2[i][1];
for(i=1;Op2[i][1];i++)
Op2[i][0]=Op2[i][1]=0;
}
for(i=1;Op[i][1]!=-INF;i++)
Op[i][0]=Op[i][1]=-INF;
for(Chain*tp=Head[u];tp;tp=tp->next)
if(!Chosen[tp->u])
{
root=0;
Max=size[tp->u]>size[u]?size[tp->u]-size[u]:size[tp->u];
FindRoot(tp->u,tp->u);
Chosen[root]=true;
Divid(root);
}
}
int n,m;
int main()
{
int i,j,k;
Heavy[0]=1<<29;
read(n),read(m),read(K);
while(m--)
read(i),read(j),read(k),Add(i,j,S,k),Add(j,i,S,k);
Dij(S,1);
done[1]=true;
Build(1);
Max=size[1];
root=0;
for(i=1;i<=K;i++)
Op[i][0]=Op[i][1]=-INF;
FindRoot(1,1);Chosen[root]=true;
Divid(root);
printf("%d %d\n",longest,Kind);
return 0;
}