题意:
给定n个节点的树,和一个整数k,
一次操作你可以选择k个叶子,要求这k个叶子都连接在同一个点上,然后删除这k个叶子,
问最多进行多少次操作。
数据范围:n<=2e5
解法:
模拟,将所有叶子节点(度数等于1的点)加入队列,
维护每个点叶子树leaf[],度数d[],访问标记mark[]
依次从队列中取出叶子,标记,该叶子的父节点叶子数leaf[x]+=1,
当出现leaf[x]==k的时候,ans++,同时leaf[x]-=k,d[x]-=k,
如果d[x]变成1,说明x变成了叶子,那么加入队列,
重复操作即可。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
vector<int>g[maxm];
int mark[maxm];
int leaf[maxm];
int d[maxm];
int n,k;
signed main(){
ios::sync_with_stdio(0);
int T;cin>>T;
while(T--){
cin>>n>>k;
for(int i=1;i<=n;i++){
g[i].clear();
d[i]=0;
}
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
d[a]++;d[b]++;
}
for(int i=1;i<=n;i++){
mark[i]=0;
leaf[i]=0;
}
queue<int>q;
for(int i=1;i<=n;i++){
if(d[i]==1){
q.push(i);
}
}
int ans=0;
while(!q.empty()){
int x=q.front();q.pop();
mark[x]=1;
for(int v:g[x]){
if(mark[v])continue;
leaf[v]++;
if(leaf[v]==k){
ans++;
d[v]-=k;
leaf[v]-=k;
if(d[v]==1){//如果变成叶子
q.push(v);
}
}
}
}
cout<<ans<<endl;
}
return 0;
}