题意:有一个这样的树。结点u、v之间的距离就是他们的边的总数。n个结点就有n*(n-1)/2个这样的距离,
就这些结点的距离按升序排序,然后算出k个这样的距离的总和。
因为树的题目做的比较少,借鉴比较多。
#include<stdio.h>
#include<string.h>
const int maxn=110000;
const int maxm=maxn<<1;
int que[maxm*10][4];
int head[maxn],pnt[maxm],nxt[maxm],e;
void init()
{
e=0;
memset(head,-1,sizeof(head));
}
void AddEdge(int u,int v)
{
pnt[e]=v;nxt[e]=head[u];head[u]=e++;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
m<<=1;
int sz=0;
init();//初始化
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
//插入两条边
AddEdge(u,v);
AddEdge(v,u);
if(sz<m)
{
que[sz][0]=u,que[sz][1]=v,
que[sz][2]=1,que[sz][3]=-1;
++sz;
}
if(sz<m)
{
que[sz][0]=v;que[sz][1]=u;
que[sz][2]=1;que[sz][3]=-1;
++sz;
}
}
int H=0,T=sz;
long long ans=0;
for(int i=0;i<m;i++)
{
int dis=que[H][2];
int u=que[H][0],v=que[H][1];
int pre=que[H][3];
++H;//一次一次遍历这个队列
for(int j=head[u];j!=-1&&T<m;j=nxt[j])
{
int uu=pnt[j];
//uu==v是排除本身重合的一个路线
//就说明这条路径是由哪一条路径拓展所得,防止算重死循环。
if(uu==v||uu==pre) continue;
que[T][0]=uu,que[T][1]=v,
que[T][2]=dis+1,que[T][3]=u;
T++;
}
ans+=dis;
}
printf("%d\n",ans>>1);
}
return 0;
}