求助QaQ 传送门:https://codeforces.com/contest/1593/problem/E 本蒟蒻采用队列存叶子节点的方法进行删叶子操作,但是一直在第二个数据点TLE,没发现代码哪里卡死循环(注,本题所有测试数据中n的总和<=400000,所以删叶子一般不会超时),所以请各位大佬求助,谢谢。(具体代码过程已经有标明注释)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define ll long long
using namespace std;
const int N=4e5+100;
int hd[N],du[N];
int n,i,t,k,cnt,x,y,rec,kk,ans;
bool vis[N];
struct star{
int ne,to;
}e[N<<1];//采用链式前向星存边
queue <int> q;//开队列存叶子
void adde(int xx,int yy)
{
e[++cnt].ne=hd[xx];
e[cnt].to=yy;
hd[xx]=cnt;
}
int main()
{
scanf("%d",&t);
while(t)
{
cnt=rec=ans=0;
kk=1;
memset(e,0,sizeof(e));
memset(hd,0,sizeof(hd));
memset(du,0,sizeof(du));
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&k);
for (i=1;i<n;i++)//存边
{
scanf("%d%d",&x,&y);
adde(x,y);
adde(y,x);
du[x]++;
du[y]++;
}
if (n <= 2)//显然能全部删除
{
printf("0\n");
t--;
continue;
}
for (i=1;i<=n;i++)
{
if (du[i] == 1) //如果是叶子节点的话就存储到队列q并统计叶子个数
{
q.push(i);
rec++;
}
}
while(kk <= k)
{
int res=0,ka,j;
if (rec == 0) break;
if (kk == k)//如果是第k次操作直接加入预删去的叶子个数
{
ans+=rec;
break;
}
while(rec > 0)//第kk次操作需导出rec个节点
{
x=q.front();
q.pop();
vis[x]=1;//vis标记该边已删除
rec--;
ans++;
if (ans >= n) break;//如果已经删去n个叶子的话就退出循环
for (j=hd[x];j;j=e[j].ne)
{
ka=e[j].to;
if (vis[ka]) continue;
du[ka]--;
if (du[ka] == 1)//删到该节点只有一条边连接时存储该节点
{
q.push(ka);
res++;//统计新叶子个数
}
}
}
rec=res;//传递叶子个数
if (ans >= n) break;
kk++;
}
ans=n-ans;
printf("%d\n",ans);
while(!q.empty()) q.pop();//清空队列剩余的节点
t--;
}
return 0;
}