好开心,终于把这一道题a了,主要是才学了树分治就来写这一道题真的有点吃不消,理解了好一会。
1.首先,对于树分治,最好是将其理解成一种思想而不是单纯的一种简单的算法,因此对于树分治的题(听学长说一般都是处理路径问题),你该怎么做就怎么做。例如这一道题,其实只要把数据给小一点就很容易想到树形dp,定义gg[i][0]:距离根节点为i的最长路径,
gg[i][1]距离根节点为i的最长路径的方案数。ff[i][0]:除开这一个子树外其他之前子树的最长路径(用于计算经过根节点与其他的子树节点相连的的路径计算)ff[i][1]:除开这一个子树外其他之前子树的最长路径的方案数。
然后就可以了啊,每一次枚举距离更新答案。
2.至于之前的处理最短树就不说了
//一开始忘了0的深度的情况
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define maxn 60020
using namespace std;
int n,m,k,f[maxn],head[maxn],tot=1,d[maxn],vis[maxn];
typedef pair<int ,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
vector<pii >g[maxn];
struct edge{
int v,w,next;
}e[120020];
struct node{
int a,b,w;
bool operator<(const node& b)const{return w<b.w;}
}nod[maxn];
void adde(int a,int b,int c){
e[tot].v=b;
e[tot].w=c;
e[tot].next = head[a];
head[a] = tot++;
}
void dijkstra(){
for(int i=0;i<=n;i++)d[i]=1e9;
d[1]=0;
vis[1]=1;
q.push(make_pair(0,1));
while(!q.empty()){
int u=q.top().second;
q.pop();
vis[u]=1;
for(int i=0;i<g[u].size();i++){
int v=g[u][i].first;
if(!vis[v]&&d[v]>d[u]+g[u][i].second){
d[v]=d[u]+g[u][i].second;
q.push(make_pair(d[v],v));
}
}
}
return;
}
bool build_vis[maxn];
void build(int u){
build_vis[u]=true;
sort(g[u].begin(),g[u].end());
for(int i=0;i<g[u].size();i++){
int v=g[u][i].first,w=g[u][i].second;
if(d[v]==d[u]+w&&!build_vis[v]){
adde(v,u,w);
adde(u,v,w);
build(v);
}
}
}
int rt,ff[maxn][3],s[maxn],gg[maxn][3],size,ans1=0,ans2=0,h[maxn],dis[maxn];//gg[i][0]表示以当前i为重心子树为重心的时候包含k个节点的最优解
//gg[i][1] 表示以i为重心的时候并且求得最长路径的的时候的路径数
void getroot(int u,int fa){
f[u]=0,s[u]=1;
for(int i=head[u];~i;i=e[i].next ){
int v=e[i].v ;
if(v==fa||vis[v])continue;
getroot(v,u);
s[u]+=s[v];
f[u]=max(f[u],s[v]);
}
f[u]=max(f[u],size-f[u]);//我去 忘了更新这里的f
if(f[u]<f[rt])rt=u;//写成了大于
}
void dfs(int u,int fa){
if(gg[h[u]][0]<dis[u]){
gg[h[u]][0]=dis[u];
gg[h[u]][1]=1;
}else if(gg[h[u]][0]==dis[u])gg[h[u]][1]++;
for(int i=head[u];~i;i=e[i].next ){
int v=e[i].v,w=e[i].w ;
if(vis[v]||v==fa)continue;
h[v]=h[u]+1;dis[v]=dis[u]+w;
dfs(v,u);
}
}
void calc(int u){
for(int i=1;i<=k;i++)ff[i][0]=0,ff[i][1]=0;
ff[0][1]=1;
for(int i=head[u];~i;i=e[i].next ){
int v=e[i].v;
if(vis[v])continue;
for(int j=1;j<=k;j++)gg[j][0]=0,gg[j][1]=0;
gg[0][1]=1;
h[u]=0;
h[v]=1,dis[v]=e[i].w;
dfs(v,u);
for(int j=1;j<k;j++){
int w;//找最长的路径
w= gg[j][0]+ff[k-j-1][0];
if(w>ans1)ans1=w,ans2=gg[j][1]*ff[k-j-1][1];
else if(w==ans1){
ans2+=gg[j][1]*ff[k-j-1][1];
}
}
for(int j=1;j<k;j++){
if(ff[j][0]<gg[j][0]){
ff[j][0]=gg[j][0];
ff[j][1]=gg[j][1];
}else if(ff[j][0]==gg[j][0]){
ff[j][1]+=gg[j][1];
}
}
}
}
void solve(int u){
vis[u]=1;
calc(u);
for(int i=head[u];~i;i=e[i].next ){
int v=e[i].v;
if(vis[v])continue;
f[0]=size=s[v];rt=0;
if(s[v]>=k-1){
getroot(v,0);
solve(rt);
}
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&k);
for(int a,b,c,i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
}
dijkstra();
memset(vis,0,sizeof(vis));
build(1);
memset(vis,0,sizeof(vis));
rt=0;f[0]=size=n;
getroot(1,rt);
solve(rt);
printf("%d %d",ans1,ans2);
return 0;
}