zoukankan      html  css  js  c++  java
  • 统一天下

    description

    给定两棵树,节点数分别为(n)(m),请你在两棵树间连接一条路径使得形成的新大树中由(N=n+m)个点两两组成的(frac{N(N-1)}{2})个点对距离之和最小.

    solution

    通过大眼观察法,我们可以得出连接处两端点分别是两棵树的重心,所以可以进行树形dp.然后(Omicron(n+m))进行扫描求解答案即可.

    至于求解答案的方法,我们可以注意到,对于每一个点(x)到其父节点的边,会有(size[x])个点在其下方,(n+m-size[x])个点在其上方,这些点两两构成点对会经过这条边,于是这条边的贡献即为(size[x]*(n+m-size[x]))

    另外值得注意的是,本题点数较多,极端情况下递归dfs会爆栈,所以要手写栈实现非递归式dfs,从来没写过的我瞎yy出来一种,凑合看吧.

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define R register
    #define next MabLcdG
    #define mod 1
    #define debug puts("mlg")
    #define Mod(x) ((x%mod+mod)%mod)
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    inline ll read();
    inline void write(ll x);
    inline void writesp(ll x);
    inline void writeln(ll x);
    const ll maxn=360000;
    ll to[maxn<<2],head[maxn<<1],next[maxn<<2],tot,w[maxn<<2];
    inline void add(ll x,ll y){to[++tot]=y;next[tot]=head[x];head[x]=tot;}
    ll n,m;
    ll siz[maxn<<1],maxs[maxn<<1];
    ll ans;
    ll root1,root2;
    
    ll _stack[2000000],h,fa[2000000];
    bool book[2000000];
    inline void dfs1(ll begin,bool type){
    	_stack[++h]=begin;
    	while(h){
    		ll x=_stack[h];
    		if(!book[x]){
    			siz[x]=1;
    			for(R ll i=head[x],ver;i;i=next[i]){
    				ver=to[i];
    				if(ver==fa[x]) continue;
    				fa[ver]=x;
    				_stack[++h]=ver;
    			}
    			book[x]=true;
    			continue;
    		}
    		else{
    			for(R ll i=head[x],ver;i;i=next[i]){
    				ver=to[i];
    				if(ver==fa[x]) continue;
    				siz[x]+=siz[ver];
    				maxs[x]=max(maxs[x],siz[ver]);
    			}
    			maxs[x]=max(maxs[x],(type?m:n)-siz[x]);
    			if(maxs[x]<maxs[type?root2:root1]) type?(root2=x):(root1=x);
    			book[x]=false;
    			--h;
    		}		
    	}
    }
    inline void dfs2(ll begin){
    	_stack[++h]=begin;
    	while(h){
    		ll x=_stack[h];
    		if(!book[x]){
    			siz[x]=1;
    			for(R ll i=head[x],ver;i;i=next[i]){
    				ver=to[i];
    				if(ver==fa[x]) continue;
    				_stack[++h]=ver;fa[ver]=x;
    			}
    			book[x]=true;
    			continue;
    		}
    		else{
    			for(R ll i=head[x],ver;i;i=next[i]){
    				ver=to[i];
    				if(ver==fa[x]) continue;
    				siz[x]+=siz[ver];
    			}
    			ans+=siz[x]*(n+m-siz[x]);
    			--h;
    			book[x]=false;
    		}
    	}
    }
    int main(){
    	freopen("unite.in","r",stdin);
    	freopen("unite.out","w",stdout);
    	maxs[0]=((ull)1<<63)-1;
    	n=read();m=read();
    	for(R ll i=1,x,y;i<n;i++){
    		x=read();y=read();
    		add(x,y);add(y,x);
    	}
    	for(R ll i=1,x,y;i<m;i++){
    		x=read()+n,y=read()+n;
    		add(x,y);add(y,x);
    	}
    	dfs1(1,0);dfs1(n+1,1);
    	add(root1,root2);add(root2,root1);
    	dfs2(1);
    	writeln(ans);
    }
    inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
    inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
    inline void writesp(ll x){write(x);putchar(' ');}
    inline void writeln(ll x){write(x);putchar('
    ');}
    //inline void dfs1(ll x,ll fa,bool type){
    //	siz[x]=1;
    //	for(R ll i=head[x],ver;i;i=next[i]){
    //		ver=to[i];
    //		if(ver==fa) continue;
    //		dfs1(ver,x,type);
    //		siz[x]+=siz[ver];
    //		maxs[x]=max(maxs[x],siz[ver]);
    //	}
    //	maxs[x]=max(maxs[x],(type?m:n)-siz[x]);
    //	if(maxs[x]<maxs[type?root2:root1]){
    //		if(type) root2=x;
    //		else root1=x;
    //	}
    //}
    //inline void dfs2(ll x,ll fa){
    //	siz[x]=1;
    //	for(R ll i=head[x],ver;i;i=next[i]){
    //		ver=to[i];
    //		if(ver==fa) continue;
    //		dfs2(ver,x);
    //		siz[x]+=siz[ver];
    //	}
    //	ans+=siz[x]*(n+m-siz[x]);
    //}
    
  • 相关阅读:
    来了!GitHub for mobile 发布!iOS beta 版已来,Android 版即将发布
    五角场之殇。曾与张江、漕河泾、紫竹齐名。如今,上海四大IT科技园是否还在?
    Visual Studio Online 的 FAQ:iPad 支持、自托管环境、Web 版 VS Code、Azure 账号等
    VS Code 1.40 发布!可自行搭建 Web 版 VS Code!
    Visual Studio Online,带来四种开发模式,未来已来。
    基于七牛云对象存储,搭建一个自己专属的极简Web图床应用(手摸手的注释讲解核心部分的实现原理)
    css伪元素::before与::after使用基础示例
    gcc生成静态链接库与动态链接库步骤,并链接生成可执行文件的简单示例
    shell求水仙花数
    shell实现简单的数组排序
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13446199.html
Copyright © 2011-2022 走看看