码迷,mamicode.com
首页 > 其他好文 > 详细

Gym101669L Divide and Conquer

时间:2020-03-26 19:09:27      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:ORC   有一个   uil   vector   for   getch   getchar   cto   clu   

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

标签:ORC   有一个   uil   vector   for   getch   getchar   cto   clu   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12576337.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!