2本の無根木所与\(A \ B \) 、\(Bの\)が正確によって\(\)の葉を追加し、その後、得られた数値は、ノードを破壊する、要求は葉を添加しますで\(B \)番号(対応葉複数の場合、出力の最小数)。
\(| A | \ leq10 ^ 5 \)
ハッシュ、DP、二次ルート変更
迅速Iが使用される式を有するハッシュを比較するために、ハッシュツリーの使用を検討することである\ displaystyle \(\(hash_u = sum_ {\テキスト{におけるV \息子(U)}}基部^ {KI-1} \回hash_u + hash_v )+ 1 \)が、エラー率が高くなる(2つの異なる値同じハッシュツリー形式を有することが容易である)、式に考慮することができる\(1 \)あるいは関連する値を持つツリーを形成するために、この質問が使用されてもよい(\ \テキスト{サイズ(U )} \)
得られたと考えることができる\(A \ B \)各ノードにハッシュ値ルートであり、そして列挙\(B \)をすべての葉でハッシュ値がツリー全体の葉を除去した後速やかに得られます。葉の場合は、上記の式によれば、\(U \)は、ハッシュ値のルートである\(X \) 、次いで除去\(U \)を全体ツリーのハッシュ値の後\(| B | X- \)
我々は、(O(Nログn \ \ )\) ツリーの各点のハッシュ値を取得するには、と呼ばれる\(F_iと\) 、表記\(G_i \)である(私は\)\、ルートのハッシュ値をトランスデューサは、二次ルート(トップダウン)を使用して考えることができます。
現在のノードがあるように(V \)\、ノードの父\(U \)、\を(g_v \)と等価である(f_v \)\ 1「以上はする\(U \)ルートは、彼の息子の削除するために、\(Vを\)ハッシュ値「息子、暴力列挙\は(U \)彼の息子がデイジーアウトピクチャーカードすることができたときに、それを式に要求される、すべてのルートです。ハッシュ値は、ルート内の各点の場合、すべての息子を記録することができる\(val_ {U、\のI} \) "ハッシュプレフィックスと"、この時点で維持\(sum_ {U、\ K} = \ DisplayStyle \ sum_ {I} = 0 {U ^ kval_、\のI} \タイムズNi基1} ^ {\)。「で\(U \)は、根を除去息子として\(V \)ハッシュ値の」削除されたシーケンスの後のポイントのハッシュ値を求めることと等価です。オーダー\(N = \ {テキストサイズ(val_u} \ {テキスト)} \) 、位置除去\(K \)得られたハッシュ値であるsum_ {U、\ nを(\ } - (sum_ {U、\ Kを-sum_ {U}、\} 1-K)\ベースタイムズNK} ^ {\) 。し、」決定(uは\)\ルート息子を削除するには\(Vの\)ハッシュ値が「オーバー掃引\(V \)処理することができる息子\(g_v、\ val_v、\ SUM_V \) 。時間複雑\(O(N \ログnを )\)
ハッシュ式は最後の項目に見出すことができる(\ \テキスト{サイズ(U )} \) のみ(低いエラーレートを満たすだけでなく、便利な転送を満たしているので、これは、ハッシュ木の良い選択である霧
時間複雑\(O(N \ログN )\)
コード
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long u64;
const int maxn = 1e5 + 10;
const u64 base = 19260817, Inv = 7089841341079321457ull;
int n;
u64 pw[maxn];
struct Tree {
int N, sz[maxn];
u64 dp1[maxn], dp2[maxn];
vector <int> e[maxn];
vector <u64> vec[maxn], sum[maxn];
u64 dfs1(int u, int f) {
sz[u] = 1;
for (int v : e[u]) {
if (v != f) vec[u].push_back(dfs1(v, u)), sz[u] += sz[v];
}
sort(vec[u].begin(), vec[u].end());
int SZ = vec[u].size(); sum[u].resize(SZ);
for (int i = 0; i < SZ; i++) {
sum[u][i] = (i ? base * sum[u][i - 1] : 0) + vec[u][i];
}
return dp1[u] = (SZ ? sum[u].back() : 0) + sz[u];
}
void dfs2(int u, int f) {
int SZ = vec[f].size();
int pos = distance(vec[f].begin(), lower_bound(vec[f].begin(), vec[f].end(), dp1[u]));
vec[u].push_back(sum[f][SZ - 1] - (sum[f][pos] - (pos ? sum[f][pos - 1] : 0)) * pw[SZ - pos - 1] + N - sz[u]);
sort(vec[u].begin(), vec[u].end());
SZ = vec[u].size(), sum[u].resize(SZ);
for (int i = 0; i < SZ; i++) {
sum[u][i] = (i ? base * sum[u][i - 1] : 0) + vec[u][i];
}
dp2[u] = sum[u].back() + N;
for (int v : e[u]) {
if (v != f) dfs2(v, u);
}
}
void build() {
for (int i = 1; i < N; i++) {
int u, v;
scanf("%d %d", &u, &v);
e[u].push_back(v), e[v].push_back(u);
}
dfs1(1, 0);
dp2[1] = dp1[1];
for (int v : e[1]) {
dfs2(v, 1);
}
}
} A, B;
set <u64> S;
int main() {
pw[0] = 1;
for (int i = 1; i < 100005; i++) {
pw[i] = base * pw[i - 1];
}
scanf("%d", &n);
A.N = n, B.N = n + 1;
A.build(), B.build();
for (int i = 1; i <= A.N; i++) {
S.insert(A.dp2[i]);
}
for (int i = 1; i <= B.N; i++) {
if (B.e[i].size() > 1) continue;
u64 x = B.dp2[i] - B.N;
if (S.find(x) != S.end()) {
printf("%d", i); return 0;
}
}
assert(0);
return 0;
}