题意:有两棵节点数同为
解析:很明显
如何判断是否在子树中呢?dfs 序!!!
于是首先把第一棵树的 dfs 序求出来,然后以 dfs 序为下标建立一个树状数组,开始遍历第二棵树。我们统计
最后把每个点的求和值加起来即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define INF 1e9
using namespace std;
const int maxn=100101;
int n,dfn1[maxn],dfn2[maxn],tot,tree[maxn];
int head1[maxn],cnt1,head2[maxn],cnt2;
int s[maxn],ans;
struct node
{
int next;
int to;
}e1[maxn<<1],e2[maxn<<1];
void add1(int from,int to)
{
e1[++cnt1].next=head1[from];
e1[cnt1].to=to;
head1[from]=cnt1;
}
void add2(int from,int to)
{
e2[++cnt2].next=head2[from];
e2[cnt2].to=to;
head2[from]=cnt2;
}
void dfs1(int u,int fa)
{
dfn1[u]=++tot;
for(int i=head1[u];i;i=e1[i].next)
{
int v=e1[i].to;
if(v==fa)
continue;
dfs1(v,u);
}
dfn2[u]=tot;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=val;
}
int query(int x)
{
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum+=tree[i];
return sum;
}
void dfs2(int u,int fa)
{
s[u]=query(dfn1[u]-1);//计算答案
add(dfn1[u],1);// 对访问过的点加贡献
add(dfn2[u],-1);
for(int i=head2[u];i;i=e2[i].next)
{
int v=e2[i].to;
if(v==fa)
continue;
dfs2(v,u);
}
add(dfn1[u],-1);
add(dfn2[u],1);//访问完,清除贡献
}
int main()
{
freopen("climb.in","r",stdin);
freopen("climb.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add1(a,b);
add1(b,a);
}
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add2(a,b);
add2(b,a);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=n;i++)
ans+=s[i];
printf("%d",ans);
return 0;
}