[dfs序]猴猴的比赛

Posted yuxiaoze

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[dfs序]猴猴的比赛相关的知识,希望对你有一定的参考价值。

题目限制
2000 ms 256 M
题目描述
猴猴今天要和小伙伴猩猩比赛爬树,为了公平不碰撞,猴猴和猩猩需要在不同的树上攀爬。于是
它们选了两颗节点数同为n的树,并将两棵树的节点分别以1~n标号(根节点标号为1),但两棵树
的节点连接方式不尽相同。
现在它们决定选择两个标号的点进行比赛。为了方便统计,规定它们比赛中必须都向上爬。(即
选定的赛段节点u→节点v都必须指向叶子方向)请你求出这两棵树上共有多少对节点满足比赛的需
求。

输入格式
第一行一个数n。(n≤100000)
接下来n-1行,每行2个数a和b,表示第一棵树a和b有树枝相连。
接下来n-1行,每行2个数a和b,表示第二棵树a和b有树枝相连。
输出格式
输出满足条件的对数。
数据范围
对于30%的数据:n≤1000
对于50%的数据:n≤10000
对于100%的数据:n≤100000,1≤a,b≤n

输入样例

输入样例1
4
1 2
2 3
3 4
1 2
2 3
2 4
输入样例2
7
1 2
1 3
2 4
1 5
5 6
6 7

1 2
1 3
3 4
4 5
3 6
1 7
输入样例3
4
1 2

1 3
3 4
1 2
1 3
3 4

输出样例
输出样例1
5
输出样例2
6
输出样例3
4

 

题解
我们可以通过dfs序对第一棵树进行编号,得到每个节点本身的编号以及子树的编号范围[li,ri]
 。 用树状数组来维护后面的计算。 在DFS处理第二棵树时,我们每处理完一个节
点,就将该节点在第一棵树中的对应编号设为1,处理完所有子节点后,查询编号区间 [li,ri]
的区间和,即当前子树下,有多少个节点在树1中也是当前节点的子孙节点。维护计数即可。 复杂
度  nlog(n).

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=100000+5;
 5 
 6 int n,num,last[N],nxt[2*N],ver[2*N];
 7 inline void add(int x,int y) 
 8  {nxt[++num]=last[x]; last[x]=num; ver[num]=y; 
 9   nxt[++num]=last[y]; last[y]=num; ver[num]=x; 
10  }
11 int id,ord[N],siz[N];
12 void pre(int x,int fa)
13  {ord[x]=++id; siz[x]=1;
14   for(int i=last[x];i;i=nxt[i])
15    {int y=ver[i];
16        if(y==fa) continue; 
17        pre(y,x); siz[x]+=siz[y];
18    }
19  }
20 int lowbit[N],t[N],ans[N];
21 inline void change(int x,int delta)
22  {while(x<=n)
23    {t[x]+=delta;
24        x+=lowbit[x];
25    }
26  }
27 inline int ask(int x)
28  {int re=0; 
29   while(x)
30    {re+=t[x]; 
31     x-=lowbit[x];
32    }
33   return re; 
34  } 
35 void dfs(int x,int fa)
36  {int cmp=0;
37   for(int i=last[x];i;i=nxt[i])
38    {int y=ver[i];
39     if(y==fa) continue;
40      cmp=ask(ord[y]+siz[y]-1)-ask(ord[y]-1); 
41      dfs(y,x); 
42      ans[y]-=cmp; 
43      change(ord[y],1); 
44    }
45   ans[x]=ask(ord[x]+siz[x]-1)-ask(ord[x]-1); 
46  } 
47 int main()
48  {    
49  freopen("climb.in","r",stdin);
50  freopen("climb.out","w",stdout);
51  int x,y; scanf("%d",&n);    
52  for(int i=1;i<n;i++) {scanf("%d%d",&x,&y); add(x,y);}
53  pre(1,0);    
54  num=0; memset(last,0,sizeof(last));     
55  for(int i=1;i<n;i++) {scanf("%d%d",&x,&y); add(x,y); }    
56  for(int i=1;i<=n;i++) lowbit[i]=i&-i;    
57  
58  dfs(1,0);    
59  for(int i=1;i<=n;i++) ans[0]+=ans[i];
60  printf("%d",ans[0]);
61 return 0;     
62  }

 

以上是关于[dfs序]猴猴的比赛的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 199 二叉树的右视图

DFS序常见用法及代码实现

DFS序详解

[bzoj1612][Usaco2008 Jan]Cow Contest奶牛的比赛_dfs

#144. DFS 序 1

攻不下dfs不参加比赛