种树
题目描述
输出所有可行节点?
数据范围
数据保证有解。
题解
众所周知,一个有n个节点的树有n-1条边,因为最终图里有n-1个节点,所以最终图有 n−2条边,因此你需要删一个度数为 m−(n−2)的结点。
因为删掉这个点后剩下的图仍然连通,所以这个点不能是割点。
用 Tarjan 算法求割点,然后输出所有不是割点且度数满足条件的结点就行了。
Code(Pascal)
var
n,m,i,j,k,h,l,o,p,top,ppp,kkk:longint;
bj:array[0..300000,1..2] of longint;
en:array[0..200000] of longint;
ss,s,kw:array[0..150000] of boolean;
bz:boolean;
zh,dfn,low,ans,ran,fa:array[0..120000] of longint;
function min(a,b:longint):Longint;
begin
if a<b then exit(a)
else exit(b);
end;
procedure kp(l,r:Longint);
var
i,j,m:longint;
begin
i:=l;
j:=r;
m:=ran[(l+r) div 2];
repeat
while ran[i]<m do inc(i);
while ran[j]>m do dec(j);
if i<=j then
begin
ran[0]:=ran[i];
ran[i]:=ran[j];
ran[j]:=ran[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then kp(l,j);
if i<r then kp(i,r);
end;
procedure qsort(l,r:longint);
var
i,j,m:longint;
begin
i:=L;
J:=R;
m:=bj[(l+r) div 2,1];
repeat
while bj[i,1]<m do inc(i);
while bj[j,1]>m do dec(j);
if i<=j then
begin
bj[0]:=bj[i];
bj[i]:=bj[j];
bj[j]:=bj[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure dg(o:longint);
var
i:longint;
begin
inc(h);
dfn[o]:=h;
low[o]:=h;
inc(top);
zh[top]:=o;
s[o]:=true;
ss[o]:=true;
if bz then exit;
for i:=en[o-1]+1 to en[o] do
if bj[i,2]<>fa[o] then
begin
if s[bj[i,2]]=false then
begin
fa[bj[i,2]]:=o;
dg(bj[i,2]);
low[o]:=min(low[o],low[bj[i,2]]);
if dfn[o]<=low[bj[i,2]] then kw[o]:=true;
if bz then exit;
end
else
if ss[bj[i,2]] then low[o]:=min(low[o],dfn[bj[i,2]]);
end;
if o=1 then
o:=1;
if bz then exit;
if dfn[o]=low[o] then
begin
p:=0;
while zh[top+1]<>o do
begin
ss[zh[top]]:=false;
inc(p);
ans[p]:=zh[top];
dec(top);
end;
if p>1 then bz:=true;
end;
end;
begin
readln(n,m);
for i:=1 to m do
begin
readln(bj[i*2-1,1],bj[i*2-1,2]);
bj[i*2,1]:=bj[i*2-1,2];
bj[i*2,2]:=bj[i*2-1,1];
inc(en[bj[i*2,1]]);
inc(en[bj[i*2,2]]);
end;
qsort(1,2*m);
for i:=2 to n do
en[i]:=en[i-1]+en[i];
fa[1]:=-1;
dg(1);
kkk:=m-(n-2);
for i:=1 to p do
if (en[ans[i]]-en[ans[i]-1]=kkk) and not(kw[ans[i]]) then
begin
inc(ppp);
ran[ppp]:=ans[i];
end;
kp(1,ppp);
if n=m+1 then
for i:=1 to n do
if en[i-1]+1=en[i] then
begin
inc(ppp);
ran[ppp]:=i;
end;
writeln(ppp);
for i:=1 to ppp do
write(ran[i],' ');
end.