51nod1681 公共祖先

基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

有一个庞大的家族,共n人。已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边)。

在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈……

两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先。

整个家族的亲密度定义为任意两个人亲密度的总和。

Input
第一行一个数n(1<=n<=100000)
接下来n-1行每行两个数x,y表示在第一个平行宇宙x是y的父亲。
接下来n-1行每行两个数x,y表示在第二个平行宇宙x是y的父亲。
Output
一个数,表示整个家族的亲密度。
Input示例
5
1 3
3 5
5 4
4 2
1 2
1 3
3 4
1 5
Output示例
6
﹡    LH  (题目提供者)



题解:

可以把问题转化一下,先计算出两棵树中的每个节点有多少个共同儿子,假设为x,那C(x, 2)就是该节点的贡献。计算每个节点有多少个共同儿子可以利用dfs序加树状数组维护。


代码:

#include<bits/stdc++.h>
using namespace std;
int n,tot,rt,a[300001],next[300001],cnt,e[300001],head[300001],dfn[300001],low[300001];
long long ans,f[300001];
void build(int t,int k){
	tot++;
	e[tot]=k;
	next[tot]=head[t];head[t]=tot;
}
void dfs(int x,int la){
	dfn[x]=++cnt;
	for(int i=head[x];i;i=next[i])
	 if(e[i]!=la){
	 	dfs(e[i],x);
	 }
	low[x]=cnt; 
}
int lowbit(int x){
	return x&(-x);
}
void insert(int x,long long t){
	for(int i=x;i<=n;i+=lowbit(i))f[i]+=t;
}
long long query(int x){
	long long sum=0;
	for(int i=x;i;i-=lowbit(i))sum+=f[i];
	return sum;
}
void dfs1(int x,int la){
	insert(dfn[x],1);
	long long sum=query(low[x])-query(dfn[x]-1);
	for(int i=head[x];i;i=next[i]){
		if(e[i]!=la)dfs1(e[i],x);
	}
	long long sum1=query(low[x])-query(dfn[x]-1);
	ans+=(sum1-sum)*(sum1-sum-1)/2;
}
int main(){
	int t,k,i;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d",&t,&k);
		build(t,k);
		a[k]++;
	}
	for(i=1;i<=n;i++)
	 if(a[i]==0){
	 	rt=i;
	 	break;
	 }
	dfs(rt,0);
	tot=0;
	memset(head,0,sizeof(head));
	memset(next,0,sizeof(next));
	memset(a,0,sizeof(a));
	for(i=1;i<n;i++){
		scanf("%d%d",&t,&k);
		build(t,k);
		a[k]++;
	} 
	for(i=1;i<=n;i++)
	 if(!a[i]){
	 	rt=i;
	 	break;
	 }
	dfs1(rt,0);
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/80574420