题解
- 无标号树的HASH:
- 找到树的重心,以重心为根求出括号序列;
- 由于树的重心最多只有两个,取字典序的最小括号序列HASH即可
- 树的括号序列$s_{u}="(s_{v_{1}},s_{v_{2}},s_{v_{3}},...,s_{v_{n}})"$,同时字典序$s_{v_{1}} <= s_{v_{2}} <= ,... $
- 有标号树的HASH:
- 个人认为可以直接$prufer$序列$HASH$
- 或者直接将儿子排个序$hash$,(总之乱搞)
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
using namespace std;
const int N=;
int n,m,hd[N],o,sz[N],mx[N],Mx,tot;
struct Edge{int v,nt;}E[N<<];
map<int,int>h;
string now,s[N],tmp[N];
void adde(int u,int v){
E[o]=(Edge){v,hd[u]};hd[u]=o++;
E[o]=(Edge){u,hd[v]};hd[v]=o++;
}
void get_rt(int u,int fa){
sz[u]=;mx[u]=;
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==fa)continue;
get_rt(v,u);
sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
}
mx[u]=max(m-sz[u],mx[u]);
if(mx[u]<Mx)Mx=mx[u];
}
void dfs(int u,int fa){
s[u]="(";
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==fa)continue;
dfs(v,u);
}
tot=;
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==fa)continue;
tmp[++tot]=s[v];
}
sort(tmp+,tmp+tot+);
for(int i=;i<=tot;i++)s[u]=s[u]+tmp[i];
s[u]+=")";
}
int main(){
#ifndef ONLINE_JUDGE
freopen("bzoj4337.in","r",stdin);
freopen("bzoj4337.out","w",stdout);
#endif
scanf("%d",&n);
for(int I=;I<=n;I++){
o=;memset(hd,-,sizeof(hd));
scanf("%d",&m);
for(int i=,x;i<=m;i++){
scanf("%d",&x);
if(x)adde(x,i);
}
Mx=m;get_rt(,);
now="";
for(int i=;i<=m;i++)if(Mx==mx[i]){
dfs(i,);
if(now<s[i])now=s[i];
}
ll x=;
for(int i=;i<(int)now.length();i++){
x = ((x<<) + now[i])%mod;
}
//printf("%s\n",now.c_str());
if(!h[x])h[x]=I;
printf("%d\n",h[x]);
}
return ;
}bzoj4337
- 无标号树的HASH: