51 nod 1681 公共祖先 (主席树+dfs序)
1681 公共祖先
有一个庞大的家族,共n人。已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边)。
在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈……
两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先。
整个家族的亲密度定义为任意两个人亲密度的总和。
第一行一个数n(1<=n<=100000)
接下来n-1行每行两个数x,y表示在第一个平行宇宙x是y的父亲。
接下来n-1行每行两个数x,y表示在第二个平行宇宙x是y的父亲。
一个数,表示整个家族的亲密度。
5
1 3
3 5
5 4
4 2
1 2
1 3
3 4
1 5
6
/*
51 nod 1681 公共祖先 (主席树+dfs序) problem:
给你两棵树, 两个节点之间的值定义为在两个棵树中有多少一直是它们的公共祖先
求任意两个点的亲密度的总和 solve:
问题可以转换成每个点能够成为多少次公共祖先. 如果lca一直是a,b的公共祖先, 那么
a,b一定在lca的子树中. 所以找出两棵树中lca点的子树中的相同点的个数,就能计算出多少对点
在两棵树中都有lca这个公共祖先. 先处理出a树的dfs序,然后用其作为b树中dfs序的值. 在a树中,如果u在lca的子树中,那么它的序号
大于dfa[lca]小于等于eda[lca],即进出值. 所以在b树的lca的子树中找出序号在[dfa[lca],eda[lca]]
之间的个数(可以主席树维护), 就是lca子树所含相同点的个数. hhh-2016/09/16-11:36:14
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <set>
#include <map>
//#define lson i<<1
//#define rson i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define scanfi(a) scanf("%d",&a)
#define scanfs(a) scanf("%s",a)
#define scanfl(a) scanf("%I64d",&a)
#define scanfd(a) scanf("%lf",&a)
#define key_val ch[ch[root][1]][0]
#define eps 1e-7
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const ll mod = 1e9+7;
const int maxn = 100010;
const double PI = acos(-1.0); template<class T> void read(T&num)
{
char CH;
bool F=false;
for(CH=getchar(); CH<'0'||CH>'9'; F= CH=='-',CH=getchar());
for(num=0; CH>='0'&&CH<='9'; num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p)
{
if(!p)
{
puts("0");
return;
}
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
} struct Edge
{
int to,next;
};
Edge edge[maxn*2];
int tot,head[maxn];
int in[maxn];
int cnt;
void ini()
{
tot = 0;
cnt = 0;
memset(in,0,sizeof(in));
memset(head,-1,sizeof(head));
}
void add_edge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int dfa[maxn],dfb[maxn],ta[maxn],tb[maxn];
int eda[maxn],edb[maxn];
void dfs(int u,int pre,int flag)
{
if(!flag) dfa[u] = ++ cnt, ta[u] = cnt;
else dfb[u] = ++ cnt, tb[cnt] = ta[u];
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre)continue;
dfs(v,u,flag);
}
if(!flag) eda[u] = cnt;
else edb[u] = cnt;
} int toa;
int lson[maxn * 30],rson[maxn * 30] ;
ll c[maxn * 30]; int build(int l,int r)
{
int root = toa ++ ;
c[root] = 0;
if(l != r)
{
int mid = (l+r) >> 1;
build(l,mid);
build(mid+ 1,r);
}
return root ;
}
int n;
int update(int root,int pos,ll val)
{
int newroot = toa ++ ,tmp = newroot;
c[newroot ] = c[root] + val;
int l = 1,r = n; while(l < r)
{
int mid = (l+r) >> 1;
if(pos <= mid)
{
lson[newroot] = toa ++ ,rson[newroot] = rson[root];
newroot = lson[newroot],root = lson[root];
r = mid;
}
else
{
rson[newroot] = toa ++ ,lson[newroot] = lson[root];
newroot = rson[newroot] ,root = rson[root];
l = mid + 1;
}
c[newroot] = c[root] + val;
}
return tmp;
} ll query(int root1,int root2,int la,int ra,int l,int r)
{
if(l >= la && r <= ra)
{
return c[root2] - c[root1];
}
int mid = (l + r) >> 1;
ll ans = 0;
if(la <= mid)
{
ans += query(lson[root1],lson[root2],la,ra,l,mid);
}
if(ra > mid)
{
ans += query(rson[root1],rson[root2],la,ra,mid+1,r);
}
return ans;
} void cal(int flag)
{
int u,v;
ini();
for(int i = 1; i < n; i++)
{
read(u),read(v);
add_edge(u,v);
add_edge(v,u);
in[v] ++ ;
}
for(int i = 1; i <= n;i++)
{
if(!in[i])
{
dfs(i,-1,flag);
break;
}
}
}
int T[maxn];
int main()
{
// freopen("in.txt","r",stdin);
read(n);
toa = 0;
cal(0);
cal(1);
T[0] = build(1,n);
for(int i = 1;i <= n;i++)
{
T[i] = update(T[i-1],tb[i],1);
}
ll ans = 0;
for(int i = 1;i <= n;i++)
{
int l = dfb[i],r = edb[i];
ll t = query(T[l],T[r],dfa[i],eda[i],1,n);
ans += 1LL*t*(t-1)/2;
}
printf("%I64d\n",ans);
return 0;
}
51 nod 1681 公共祖先 (主席树+dfs序)的更多相关文章
- 「10.19」最长不下降子序列(DP)·完全背包问题(spfa优化DP)·最近公共祖先(线段树+DFS序)
我又被虐了... A. 最长不下降子序列 考场打的错解,成功调了两个半小时还是没A, 事实上和正解的思路很近了,只是没有想到直接将前$D$个及后$D$个直接提出来 确实当时思路有些紊乱,打的时候只是将 ...
- 【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序
[BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n n ...
- BZOJ3772 精神污染 【主席树 + dfs序】
题目 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海 ...
- 刷题总结——谈笑风生(主席树+dfs序的应用)
题目: Description 设T 为一棵有根树,我们做如下的定义:• 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道高明到哪里去了”.• 设a 和 b 为 T 中的两个不同 ...
- bzoj 3772 精神污染 主席树+dfs序
精神污染 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 637 Solved: 177[Submit][Status][Discuss] Descri ...
- 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增
3545: [ONTAK2010]Peaks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1202 Solved: 321[Submit][Sta ...
- 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)
http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...
- BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]
传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...
- BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序
BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with ...
随机推荐
- Alpha冲刺Day2
Alpha冲刺Day2 一:站立式会议 今日安排: 首先完善前一天的剩余安排工作量,其次我们把项目大体分为四个模块:数据管理员.企业人员.第三方机构.政府人员.数据管理员这一模块,数据管理员又可细分为 ...
- iOS开发点滴-添加阴影效果
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:_backView.bounds]; _backView.layer.masks ...
- 自主学习之RxSwift(一) -----Driver
对于RxSwift,我也是初学者,此系列来记录我学习RxSwift的历程! (一) 想必关于Drive大家一定在RxSwift的Demo中看到过,也一定有些不解,抱着一起学习的态度,来了解一下Driv ...
- 前端面试题之html
1.简述<!DOCTYPE> 的作用,标准模式和兼容模式各有什么区别? <!DOCTYPE> 位于文档的第一行,告知浏览器使用哪种规范. 如果不写DOCTYPE,浏览器会进入混 ...
- 关于搭建MyBatis框架(二)
由于在[关于使用Mybatis的使用说明(一)http://www.cnblogs.com/zdb292034/p/8675766.html]中存在不太完善地方,通过此片文档进行修订: 阅读指南:(1 ...
- 静态链表C语言数据结构
静态链表就是将数组实现单链表: int Malloc_SLL(StaticLinkList space) { int i = space[0].cur;//取得第一个头节点的下标 if( space[ ...
- 使用 dynamic 类型让 ASP.NET Core 实现 HATEOAS 结构的 RESTtful API
上一篇写的是使用静态基类方法的实现步骤: http://www.cnblogs.com/cgzl/p/8726805.html 使用dynamic (ExpandoObject)的好处就是可以动态组 ...
- OAuth2.0学习(2-1)Spring Security OAuth2.0 开发指南
开发指南:http://www.cnblogs.com/xingxueliao/p/5911292.html Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际 ...
- python的单元测试
单元测试实际上就是一些"断言"(assert)代码 断言就是判断一个函数或对象的一个方法所产生的结果是否符合你期望的那个结果. python中assert断言是声明布尔值为真的判定 ...
- 其实你并不懂如何定义一个 PHP 函数
<?php function divide($dividend, $divisor){ return $dividend / $divisor; } echo divide(12, 4); ec ...