LP4323 [JSOI2016]独特的树叶 [树的同构]

ajcxsu
ajcxsu 2018年08月26日
  • 37 次阅读

无根树的同构

Problem

B树是A树添加一个叶子节点并且打乱点编号顺序输出,删除编号最小的叶子节点使得B与A同构。

Solution

对树进行hash

具体怎么hash这里讲的很清楚:https://www.luogu.org/blog/rabbithu/solution-p4323

基本上不会碰撞吧...?

几点要注意的地方,写在了代码里。
具体来说:点数记得+1,数组记得清空,后缀hash记得初始化一个0....

Code

// Code by ajcxsu
// Problem: leaves

#include<bits/stdc++.h>
#define MOD (1000000009ll)
using namespace std;
typedef long long ll;

const int N=1e5+10, M=4e5+10, W=233;
int h1[N], h2[N], to[M], nexp[M], p=1;
int deg[N];
inline void ins(int h[], int a, int b) { nexp[p]=h[a], h[a]=p, to[p]=b, p++; }
ll f[N], g[N], pl[N], r[N];
int siz[N];
vector<ll> v1[N], v2;
set<ll> ha;
ll hal[N], har[N];

int ans=0x3f3f3f3f;
void dfs1(int h[], int x, int fr) {
    f[x]=0; // important
    v1[x].clear();
    siz[x]=1;
    for(int u=h[x];u;u=nexp[u])
        if(to[u]!=fr) {
            dfs1(h, to[u], x);
            v1[x].push_back(f[to[u]]), siz[x]+=siz[to[u]];
        }
    if(v1[x].empty()) { f[x]=1; return; }
    sort(v1[x].begin(), v1[x].end());
    for(int i=0, j=v1[x].size(); i<j; i++)
        f[x]=(f[x]*W+v1[x][i])%MOD;
    f[x]=f[x]*siz[x]%MOD;
}
int n, u, v;
void dfs2(int h[], int x, int fr, char con=0) {
    v2.clear();
    if(fr) v2.push_back(g[x]);
    for(int u=h[x];u;u=nexp[u])
        if(to[u]!=fr) v2.push_back(f[to[u]]);
    sort(v2.begin(), v2.end());
    int len=v2.size();
    for(int i=1;i<=len;i++) hal[i]=(hal[i-1]*W+v2[i-1]) % MOD;
    har[len+1]=0; // important
    for(int i=len;i>=1;i--) har[i]=(har[i+1]+v2[i-1]*pl[len-i]) % MOD;
    r[x]=hal[len];
    if(con) ha.insert(r[x]*n%MOD);
    else if(deg[x]==1 && ((fr && ha.count(g[x])) || (!fr && ha.count(f[to[h[x]]]))))
        ans=min(ans, x);
    for(int u=h[x];u;u=nexp[u])
        if(to[u]!=fr) {
            int k=lower_bound(v2.begin(), v2.end(), f[to[u]])-v2.begin();
            g[to[u]]=(n-siz[to[u]])*(hal[k]*pl[len-k-1]%MOD+har[k+2])%MOD;
            if(len==1) g[to[u]]=1;
        }
    for(int u=h[x];u;u=nexp[u])
        if(to[u]!=fr) dfs2(h, to[u], x, con);
}

int main() {
    ios::sync_with_stdio(false);
    pl[0]=1;
    for(int i=1;i<N;i++) pl[i]=(pl[i-1]*W)%MOD;
    cin>>n;
    for(int i=1;i<n;i++) cin>>u>>v, ins(h1, u, v), ins(h1, v, u);
    for(int i=1;i<=n;i++) cin>>u>>v, ins(h2, u, v), ins(h2, v, u), deg[u]++, deg[v]++;
    dfs1(h1, 1, 0), dfs2(h1, 1, 0, 1), n++;
    dfs1(h2, 1, 0), dfs2(h2, 1, 0);
    cout<<ans<<endl;
    return 0;
}

本文链接:https://acxblog.site/archives/sol-luogu-4323.html
本文采用 CC BY-NC-SA 3.0 协议进行许可