题意:给你一颗n个点的树,让你把树分成n/k块,即每块要有k个点,然后每块里面的k个点都要是连通的才行。
先预处理出每个点对应的子树的大小,若是k的倍数则记录,然后按子树的大小,由小到大打印对应子树。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct edge
{
int v,nxt;
edge(int v=0,int nxt=0)
{
this->v=v;
this->nxt=nxt;
}
};
edge e[2*maxn];
int dp[maxn],father[maxn],head[maxn],tmp[maxn],n,k,cnt;
vector<int>v[maxn];
bool vis[maxn],flag;
inline void dfs1(int now,int fa)
{
father[now]=fa;
dp[now]=1;
for(int i=head[now];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if(v==father[now]) continue;
dfs1(v,now);
dp[now]+=dp[v];
}
if(dp[now]%k==0) tmp[dp[now]]++,v[dp[now]].push_back(now),cnt++;
}
inline void dfs2(int now)
{
if(flag) printf(" ");
printf("%d",now);
flag=1;
vis[now]=1;
for(int i=head[now];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if(vis[v]||v==father[now]) continue;
dfs2(v);
}
}
int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cnt=0;
n=read();
k=read();
for(int i=1;i<=n;i++) {head[i]=-1,vis[i]=0,tmp[i]=0; if(i%k==0) v[i].clear();}
for(int i=1;i<n;i++)
{
int u,v;
u=read();
v=read();
e[cnt]=edge(v,head[u]);
head[u]=cnt++;
e[cnt]=edge(u,head[v]);
head[v]=cnt++;
}
cnt=0;
dfs1(1,0);
if(n/k!=cnt)
{
printf("NO\n");
continue;
}
printf("YES\n");
for(int i=k;i<=n;i+=k)
if(tmp[i])
{
for(int j=0;j<v[i].size();j++)
{
flag=0;
dfs2(v[i][j]);
printf("\n");
}
}
}
return 0;
}