有乙個龐大的家族,共n人。已知這n個人的祖輩關係正好形成樹形結構(即父親向兒子連邊)。
在另乙個未知的平行宇宙,這n人的祖輩關係仍然是樹形結構,但他們相互之間的關係卻完全不同了,原來的祖先可能變成了後代,後代變成的同輩……
兩個人的親密度定義為在這兩個平行宇宙有多少人一直是他們的公共祖先。
整個家族的親密度定義為任意兩個人親密度的總和。第一行乙個數n(1<=n<=100000)
接下來n-1行每行兩個數x,y表示在第乙個平行宇宙x是y的父親。
接下來n-1行每行兩個數x,y表示在第二個平行宇宙x是y的父親。乙個數,表示整個家族的親密度。
5很神奇的資料結構題,首先,我們先dfs便歷第一棵樹,記錄每個點的入時間戳和出時間戳(這點和tarjan類似),對於第二棵樹,我們也進行一遍dfs,對於每乙個節點u,我們先記錄在第二棵樹上,不包含u這個節點的子樹時,有多少節點在u所包含的時間戳裡出現過,因為出現過就知道這個點所覆蓋的時間戳一定不是以u為祖先了,之後我們來便歷第二棵樹中u的子樹,並在便歷完之後重新統計有多少個節點在u所包含的時間戳裡出現過,兩次答案相減,便是兩棵子樹中都以u為祖先的節點數,設這個差為sum,則這個節點u對答案的貢獻為(sum-1)*(sum-2),對於統計u所包含的時間戳中的結點個數,我們可以用樹狀陣列來維護,**如下:1 3
3 5
5 4
4 2
1 2
1 3
3 4
1 5
#include
#include
#include
#include
using
namespace
std;
vector
edge[100010];
vector
pic[100010];
long
long tree[10000000];
struct nodedfn[100010];
int cnt,in[100010],n;
long
long ans;
int lowbit(int x)
void dfs1(int u,int fa)
dfn[u].out=cnt;
}long
long query(int x)
return ans;
}void add(int x,int val)
}void dfs2(int u,int fa)
sum=query(dfn[u].out)-query(dfn[u].in-1)-sum-1;
ans+=(sum-1)*sum/2;
}int main()
for (int i=1;i<=n;i++)
if (!in[i]) dfs1(i,-1);
memset(in,0,sizeof(in));
for (int i=1;iint 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;}
51nod 1681公共祖先
1681 公共祖先 有乙個龐大的家族,共n人。已知這n個人的祖輩關係正好形成樹形結構 即父親向兒子連邊 在另乙個未知的平行宇宙,這n人的祖輩關係仍然是樹形結構,但他們相互之間的關係卻完全不同了,原來的祖先可能變成了後代,後代變成的同輩 兩個人的親密度定義為在這兩個平行宇宙有多少人一直是他們的公共祖先...
51nod1681 公共祖先
1681 公共祖先 基準時間限制 1 秒 空間限制 131072 kb 分值 80 難度 5級演算法題 有乙個龐大的家族,共n人。已知這n個人的祖輩關係正好形成樹形結構 即父親向兒子連邊 在另乙個未知的平行宇宙,這n人的祖輩關係仍然是樹形結構,但他們相互之間的關係卻完全不同了,原來的祖先可能變成了後...
公共祖先 51Nod 1681
給兩棵樹 問對於每對頂點 有多少除這兩個點之外的點 在這兩棵樹上都是這兩個點的公共祖先 考慮每個點的貢獻 對於乙個點 其子樹在兩棵樹上的有兩個dfs序 就看這兩個序列有多少數是相同的 c n,2 一下即可 至於查詢兩個序列的兩個區間有所少數是相同的 主席樹搞一下就行 這有個這型別的裸題 先把這個做明...