https://www.luogu.org/problem/P5258
题目描述
Waldives 有 NN 个小岛。目前的交通系统中包含 N-1N−1 条快艇专线,每条快艇专线连接两个岛。这 N-1N−1条快艇专线恰好形成了一棵树。
由于特殊的原因,所有 N-1N−1 条快艇专线都是单向的。这导致了很多岛屿之间 不能相互到达。因此,Waldives 政府希望新建一些公交线路,使得建设完毕后,任意两个小岛都可以互相到达。为了节约开支,政府希望建设最少的公交线路。
同时,出于规划考虑,每一条公交线路都有如下的要求:
1、每一条交通线路包含若干条连续的快艇专线,你可以认为一条公交线路 对应树上的一条路径,而其所包含的若干快艇专线则对应树上被这条路 径所覆盖的树边(也就是之前已经存在的某个快艇专线);
2、显然一条交通线路只能覆盖树上任意一条边至多一次;
3、公交线路中所包含的每一个快艇专线都是有方向的,并且与其所覆盖的 树边的方向相反;
4、不同的公交线路可以覆盖树上相同的点或者相同的边。
Waldives 的 NN 个岛屿分别从 00 到 N-1N−1 编号。现在给出 Waldives 已有的快艇专线信息,请计算最少所需要新建的交通线路的数量。
输入格式
第一行包含一个整数 NN。
接下来 N-1N−1行,每行包含两个整数 x,~yx, y。表示存在一条从岛屿 xx 开往岛屿 yy 的快艇专线。
输出格式
输出一行一个整数,表示需要建设的最少的交通线路数量。
注意“不同的公交线路可以覆盖树上相同的点或者相同的边”
这样就可以树形dp了
#include<iostream> #include<cstdio> #include<algorithm> #define ri register int #define u int #define NN 1000005 namespace opt { inline u in() { u x(0),f(1); char s=getchar(); while(s<'0'||s>'9') { if(s=='-') { f=-1; } s=getchar(); } while(s>='0'&&s<='9') { x=(x<<1)+(x<<3)+s-'0'; s=getchar(); } return x*f; } } namespace mainstay { u N,ans,in[NN],out[NN]; u cnt,h[NN]; struct node { u to,next; } a[NN<<1]; inline void add(const u &x,const u &y) { a[++cnt].next=h[x],a[cnt].to=y,h[x]=cnt; } void dfs(const u &x,const u &prt) { for(ri i(h[x]); i; i=a[i].next) { u _y(a[i].to); if(_y^prt) { dfs(_y,x); if(i&1) { ans+=out[_y]; in[x]+=std::max(1,in[_y]); } else { ans+=in[_y]; out[x]+=std::max(1,out[_y]); } } } u _mi(std::min(in[x],out[x])); ans+=_mi,in[x]-=_mi,out[x]-=_mi; } inline void solve() { N=opt::in(); for(ri i(1); i<N; ++i) { u _a(opt::in()+1),_b(opt::in()+1); add(_a,_b),add(_b,_a); } dfs(1,0); printf("%d",ans+std::max(in[1],out[1])); } } int main() { //freopen("x.txt","r",stdin); mainstay::solve(); }