【题解】点分治+树形dp
首先处理字典序最小的最短路径树。显然知道树上节点到顶点 1 距离最短,为了保证字典序将边排序,做个 spfa 求最短路(或者 dijkstra+heap 优化),再一遍 dfs 建树。
接下来,依然按照点分治的基本思路将路径分为是否经过当前树根节点两类。
考虑经过根节点情况。我们记 x 为根节点(重心):
每一次我们先 bfs 处理 ff 和 gg数组。再用当前子树信息和之前存下的信息更新答案和方案数。做完以后将子树信息和其他信息合并。
{ 总而言之树分治的细节总是很多,打和调试分不同过程想清楚就好啦 (⊙v⊙) }
【呆马 ( ⊙o⊙ )】
#include
#include
#include
#include
#define inf 1000000000
#define maxn 30005
struct edge{ int to,s,nxt;}e[maxn*4],e1[maxn*4];
struct edge1{ int u,v,w;}a[maxn*4];
int n,m,k,ans,sum,cnt,mx,tot,rt,fi[maxn],fi1[maxn],s[maxn],d[maxn],num[maxn],
p[maxn],q[maxn*8],f[maxn],g[maxn],ff[maxn],gg[maxn];
bool bo[maxn];
void add1(int u,int v,int w)
{
e1[++cnt].to=v;e1[cnt].s=w;
e1[cnt].nxt=fi1[u];fi1[u]=cnt;
}
void add(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].s=w;
e[cnt].nxt=fi[u];fi[u]=cnt;
}
void spfa(int x)
{
int h,t;bo[1]=true;
for (d[q[h=t=1]=x]=0;h<=t;bo[q[h++]]=false)
for (int i=fi1[q[h]];i;i=e1[i].nxt)
if (d[q[h]]+e1[i].sq[h]]+e1[i].s;
if (bo[e1[i].to]) continue;
bo[q[++t]=e1[i].to]=true;
}
}
void dfs(int x)
{
bo[x]=true;
for (int i=fi1[x];i;i=e1[i].nxt)
if (!bo[e1[i].to] && d[x]+e1[i].s==d[e1[i].to])
{
add(x,e1[i].to,e1[i].s);
add(e1[i].to,x,e1[i].s);
dfs(e1[i].to);
}
}
void findrt(int x,int fa)
{
s[x]=1;int mxx=0;
for (int i=fi[x];i;i=e[i].nxt)
if (e[i].to!=fa && !bo[e[i].to])
{
findrt(e[i].to,x);
mxx=std::max(mxx,s[e[i].to]);
s[x]+=s[e[i].to];
}
mxx=std::max(tot-s[x],mxx);
if (mxxx;
}
void bfs(int x,int s)
{
int h,t;
num[x]=1;d[x]=s;
for (q[h=t=1]=x;h<=t && num[q[h]]<=k-1;++h)
{
for (int j=fi[q[h]];j;j=e[j].nxt)
if (!bo[e[j].to] && e[j].to!=p[q[h]])
{
num[e[j].to]=num[q[h]]+1;
d[e[j].to]=d[q[h]]+e[j].s;
p[q[++t]=e[j].to]=q[h];
}
if (d[q[h]]>ff[num[q[h]]])
ff[num[q[h]]]=d[q[h]],gg[num[q[h]]]=1;
else gg[num[q[h]]]+=(d[q[h]]==ff[num[q[h]]]);
}
}
void dp(int x,int y)
{
bo[x]=true;g[0]=1;
for (int i=fi[x];i;i=e[i].nxt)
if (!bo[e[i].to])
{
p[e[i].to]=x;
bfs(e[i].to,e[i].s);
for (int j=1;jint w=ff[j]+f[k-j-1];
if (w>ans) ans=f[k-j-1]+ff[j],sum=g[k-j-1]*gg[j];
else sum+=(w==ans)*g[k-j-1]*gg[j];
}
for (int j=1;jif (ff[j]>f[j]) f[j]=ff[j],g[j]=gg[j];
else g[j]+=gg[j]*(ff[j]==f[j]);
for (int j=1;j0;
}
for (int i=0;i0;
for (int i=fi[x];i;i=e[i].nxt)
if (!bo[e[i].to])
{
if (s[e[i].to]>s[x]) s[e[i].to]=y-s[x];
rt=0;tot=mx=s[e[i].to];
if (s[e[i].to]>=k-1) findrt(e[i].to,0);
dp(rt,s[e[i].to]);
}
}
bool comp(edge1 x,edge1 y){ return x.v>y.v;}
int main()
{
scanf("%d%d%d\n",&n,&m,&k);
for (int i=1;i<=m;++i)
{
int u,v,w;
scanf("%d%d%d\n",&u,&v,&w);
a[++tot].u=u;a[tot].v=v;a[tot].w=w;
a[++tot].u=v;a[tot].v=u;a[tot].w=w;
}
std::sort(a+1,a+tot+1,comp);
for (int i=1;i<=tot;++i) add1(a[i].u,a[i].v,a[i].w);
for (int i=2;i<=n;++i) d[i]=inf;
spfa(1);cnt=0;dfs(1);
memset(bo,false,sizeof(bo));
rt=0;tot=mx=n;findrt(1,0);
ans=sum=0;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(ff,0,sizeof(ff));
memset(gg,0,sizeof(gg));
dp(rt,n);
printf("%d %d\n",ans,sum);
return 0;
}