Gym101669L Divide and Conquer
Posted cjoiershiina-mashiro
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym101669L Divide and Conquer相关的知识,希望对你有一定的参考价值。
Link
首先答案显然不可能是(1)。
然后有一个很显然的方法是把度数最小的点的所有边删掉,注意到总的度数为(4n-4),所以一定存在某个点度数不大于(3),因此答案不大于(3)。
那么可行的答案就只有(2,3)。
也就是说要么两棵树各割掉一条边,要么一棵树割一条边另一棵树割两条边。
我们枚举割掉第一棵树上的哪条边,然后计算在另一棵树上分开这两个连通块所需要割掉的最小边数,这个可以用差分进行维护。
注意如果求出来的答案为(3),那么我们还需要再在另一棵树上再枚举一遍。
#include<cstdio>
#include<cctype>
#include<vector>
const int N=300007;
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int n,ans,cnt;
struct Tree
{
std::vector<int>e[N];int col[N],size[N],son[N];
void dfs(int u,int fa){size[u]=1;for(int v:e[u])if(v^fa)if(dfs(v,u),size[u]+=size[v],size[v]>size[son[u]])son[u]=v;}
void build(){for(int i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);dfs(1,0);}
int color(int u){int tot=0;col[u]=1;for(int v:e[u])tot+=col[v]?-1:1;return tot;}
void reset(int u,int fa,Tree*t){t->col[u]=0;for(int v:e[u])if(v^fa)reset(v,u,t);}
int color(int u,int fa,Tree*t){int tot=t->color(u);for(int v:e[u])if(v^fa)tot+=color(v,u,t);return tot;}
int cal(int u,int fa,Tree*t)
{
if(!u) return 0;
for(int v:e[u]) if(v^fa&&v^son[u]) cal(v,u,t),reset(v,u,t);
int tot=cal(son[u],u,t)+t->color(u)+1;
for(int v:e[u]) if(v^fa&&v^son[u]) tot+=color(v,u,t);
if(u^1) ans>tot? ans=tot,cnt=1:cnt+=ans==tot;
return tot-1;
}
}t1,t2;
int main()
{
n=read(),ans=3,t1.build(),t2.build(),t1.cal(1,0,&t2);
if(ans==3) t2.cal(1,0,&t1);
printf("%d %d",ans,cnt);
}
以上是关于Gym101669L Divide and Conquer的主要内容,如果未能解决你的问题,请参考以下文章