1681 公共祖先
2017-10-25 18:00
447 查看
1681 公共祖先
Description
有一个庞大的家族,共n人。已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边)。
在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈……
两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先。
整个家族的亲密度定义为任意两个人亲密度的总和。
Input
第一行一个数n(1<=n<=100000)
接下来n-1行每行两个数x,y表示在第一个平行宇宙x是y的父亲。
接下来n-1行每行两个数x,y表示在第二个平行宇宙x是y的父亲。
Output
一个数,表示整个家族的亲密度。
Input example
51 3
3 5
5 4
4 2
1 2
1 3
3 4
1 5
Output example
6Solution
很神奇的数据结构题,首先,我们先dfs便历第一棵树,记录每个点的入时间戳和出时间戳(这点和tarjan类似),对于第二棵树,我们也进行一遍dfs,对于每一个节点u,我们先记录在第二棵树上,不包含u这个节点的子树时,有多少节点在u所包含的时间戳里出现过,因为出现过就知道这个点所覆盖的时间戳一定不是以u为祖先了,之后我们来便历第二棵树中u的子树,并在便历完之后重新统计有多少个节点在u所包含的时间戳里出现过,两次答案相减,便是两棵子树中都以u为祖先的节点数,设这个差为sum,则这个节点u对答案的贡献为(sum-1)*(sum-2),对于统计u所包含的时间戳中的结点个数,我们可以用树状数组来维护,代码如下:
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; vector <int> edge[100010]; vector <int> pic[100010]; long long tree[10000000]; struct node{ int in,out; }dfn[100010]; int cnt,In[100010],n; long long ans; int lowbit(int x){ return x&(-x); } void dfs1(int u,int fa){ dfn[u].in=++cnt; for (int i=0;i<edge[u].size();i++){ int v=edge[u][i]; if (v==fa) continue; dfs1(v,u); } dfn[u].out=cnt; } long long query(int x){ long long ans=0; for (int i=x;i;i-=lowbit(i)){ ans+=tree[i]; } return ans; } void add(int x,int val){ for (int i=x;i<=n;i+=lowbit(i)){ tree[i]+=val; } } void dfs2(int u,int fa){ long long sum=query(dfn[u].out)-query(dfn[u].in-1); add(dfn[u].in,1); for (int i=0;i<pic[u].size();i++){ int v=pic[u][i]; if (v==fa) continue; dfs2(v,u); } sum=query(dfn[u].out)-query(dfn[u].in-1)-sum-1; ans+=(sum-1)*sum/2; } int main(){ scanf("%d",&n); for (int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); edge[u].push_back(v); In[v]++; } for (int i=1;i<=n;i++) if (!In[i]) dfs1(i,-1); memset(In,0,sizeof(In)); for (int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); pic[u].push_back(v); In[v]++; } for (int i=1;i<=n;i++) if (!In[i]) dfs2(i,-1); printf("%lld\n",ans); return 0; }
a40b
相关文章推荐
- 51nod 1681 公共祖先 (在这两个平行宇宙有多少人一直是他们的公共祖先)
- 51Nod-1681-公共祖先
- 51nod 1681 公共祖先 主席树dfs序
- 51Nod 1681 公共祖先 [主席树做法]
- 【DFS序+树状数组】51Nod 1681 公共祖先
- 51Nod 1681 公共祖先 [树状数组做法]
- 51nod 1681 公共祖先【树状数组】【DFS序】
- 51 nod 1681 公共祖先 (主席树+dfs序)
- 51nod 1681 公共祖先 | 树状数组
- 51nod 1681 公共祖先
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- 最近公共祖先LCA:Tarjan算法
- 最近公共祖先问题
- 树的两个结点的最低公共祖先
- hihocoder 1067 最近公共祖先·二(tarjan LCA 离线算法O(n))
- 求俩个节点的最低公共祖先
- 二叉树(12)----查找两个节点最低祖先节点(或近期公共父节点等),递归和非递归
- 【剑指offer】 面试题50: 树中两个结点的最低公共祖先
- LeetCode 236 最近公共祖先 Lowest Common Ancestor of a Binary Tree
- 获得二叉树中两个节点的所有公共祖先