bzoj4754 [JSOI2016]ユニークな葉

bzoj4754 [JSOI2016]ユニークな葉

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;
}

おすすめ

転載: www.cnblogs.com/Juanzhang/p/11332632.html