HYSBZOJ 4754 [Jsoi2016]獨特的樹葉
題目大意
分析
這道題顯然考察的是樹哈希。
我這裏採用的方法是:
其中表示質數序列,表示以爲根的子樹的大小,表示以爲根的子樹的哈希值。
現在的要求就是對於和中的每個節點,求出以該節點爲根的整棵樹的哈希值。
這樣的話,我們考慮換根。
設爲去掉這棵子樹後的整棵樹的哈希值,不難得出:
其中表示以當前節點爲根,整棵樹的哈希值。的表達式我們也不難得出:
這裏我用節點爲根。
然後我們將的所有哈希值塞進set
或者map
裏面去。再枚舉中的每一個點,將它接到一個虛擬的點上面去,算出新的哈希值,找到最小的那個節點就是了。
總時間複雜度爲。
參考代碼
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int Maxn = 1e5;
const int P = 1e7;
ull SEED[Maxn + 5];
void calcSEED() {
static bool ispri[P + 5];
int cnt = 0;
for(int i = 2; i <= P; i++) {
if(!ispri[i])
SEED[++cnt] = i;
for(int j = 1; i * SEED[j] <= P && j <= cnt; j++) {
ispri[i * SEED[j]] = true;
if(i % SEED[j] == 0) break;
}
}
}
struct Graph {
struct Edge {
int to;
Edge *nxt;
};
Edge pool[Maxn * 2 + 5];
Edge *G[Maxn + 5], *ecnt;
void init() {
memset(G, 0, sizeof G);
ecnt = &pool[0];
}
void addedge(int u, int v) {
Edge *p = ++ecnt;
p->to = v, p->nxt = G[u];
G[u] = p;
}
ull hashval[Maxn + 5];
ull f[Maxn + 5], g[Maxn + 5];
int siz[Maxn + 5];
void dfs1(int u, int fa) {
f[u] = siz[u] = 1;
for(Edge *p = G[u]; p != NULL; p = p->nxt) {
int v = p->to;
if(v == fa) continue;
dfs1(v, u);
siz[u] += siz[v], f[u] += SEED[siz[v]] * f[v];
}
}
void dfs2(int u, int fa) {
if(fa != 0) g[u] = hashval[fa] - f[u] * SEED[siz[u]];
if(fa == 0) hashval[u] = f[u];
else hashval[u] = f[u] + g[u] * SEED[siz[1] - siz[u]];
for(Edge *p = G[u]; p != NULL; p = p->nxt) {
int v = p->to;
if(v == fa) continue;
dfs2(v, u);
}
}
void calc_hash() {
dfs1(1, 0);
dfs2(1, 0);
}
};
int N;
Graph A, B;
map<ull, int> s;
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
calcSEED();
A.init(), B.init();
scanf("%d", &N);
for(int i = 1; i < N; i++) {
int u, v;
scanf("%d %d", &u, &v);
A.addedge(u, v), A.addedge(v, u);
}
for(int i = 1; i <= N; i++) {
int u, v;
scanf("%d %d", &u, &v);
B.addedge(u, v), B.addedge(v, u);
}
A.calc_hash(), B.calc_hash();
for(int i = 1; i <= N + 1; i++)
if(!s.count(B.hashval[i])) s[B.hashval[i]] = i;
else s[B.hashval[i]] = min(s[B.hashval[i]], i);
for(int i = 1; i <= N; i++)
if(s.count(1 + A.hashval[i] * SEED[N])) {
printf("%d\n", s[1 + A.hashval[i] * SEED[N]]);
break;
}
return 0;
}