题意
cf219d
一棵n个点n-1条有向边的树,求翻转最少的边,使这些个点都联通,问这样的点,从小到大输出
题解
既然要求翻转的最少,那我们可以给正向的边权值为0,反向的权值为1。这样以每个点为根时,整棵树的值就是需要翻转的边数
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 220000
int ans[N],d[N],h[N],n,num=0,data[N],tot=0,mn=N;
struct node{int x,y,z,next;}mp[N<<1];
void insert(int x,int y){
mp[++num].x=x;mp[num].y=y;mp[num].z=0;mp[num].next=h[x];h[x]=num;
mp[++num].x=y;mp[num].y=x;mp[num].z=1;mp[num].next=h[y];h[y]=num;
}
void dfs1(int u){
ans[u]=0;
for(int i=h[u];i;i=mp[i].next){
int v=mp[i].y;if(d[v]) continue;
d[v]=d[u]+1;dfs1(v);ans[u]+=ans[v]+mp[i].z;
}
}
void dfs2(int u){
if(ans[u]<mn) mn=ans[u],tot=0,data[++tot]=u;
else if(ans[u]==mn) data[++tot]=u;
for(int i=h[u];i;i=mp[i].next){
int v=mp[i].y;if(d[v]!=d[u]+1) continue;
ans[v]=ans[u];
if(mp[i].z) ans[v]--;else ans[v]++;
dfs2(v);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
insert(x,y);
}d[1]=1;dfs1(1);dfs2(1);sort(data+1,data+tot+1);
printf("%d\n",mn);
for(int i=1;i<=tot;i++) printf("%d ",data[i]);
return 0;
}