zoukankan      html  css  js  c++  java
  • [bzoj4474][Jsoi2015]isomorphism【树哈希】

    【题目链接】
      https://www.lydsy.com/JudgeOnline/problem.php?id=4474
    【题解】
      先求出重心,(如果有两个重心就再新建一个点作为新重心),将无根树转化为有根树。然后再对有根树进行哈希。对于一棵子树,它的哈希值的计算方法是:
      1.求出树根节点的每个儿子的子树的哈希值。
      2.将这些哈希值排序。
      3.每次加上一个儿子的哈希值乘以进制D + 常数 C。
      4.将得到的结果开平方。
      可以证明,这种构造哈希函数的方法是比较合理的。
      时间复杂度 : O(NlogN)
    【代码】

    /* --------------
        user Vanisher
        problem bzoj-4474 
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    inf     0x3f3f3f3f
    # define    N       10010
    # define    M       21
    using namespace std;
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    const ll P=998244353, S=20011216, Q=19260817, B=2333333;
    struct Edge{
        int data,next;
    }e[N*2];
    struct Node{
        int num; ll sum;
    }fin[M];
    int m, n, deg[N], head[N], place, id, nexv[N], nexu[N], p[N], num, size[N], mx[N], tmp, rt;
    ll now[N], h[N];
    void build(int u, int v){
        e[++place].data=v; e[place].next=head[u]; head[u]=place;
    }
    bool cmp(Node x, Node y){
        return x.sum<y.sum;
    }
    void del(int x, int fa, int an){
        if (deg[x]!=2){
            if (an!=0) nexu[++num]=x, nexv[num]=an;
            for (int ed=head[x]; ed!=0; ed=e[ed].next)
                if (e[ed].data!=fa) del(e[ed].data,x,x);
        }
        else {
            for (int ed=head[x]; ed!=0; ed=e[ed].next)
                if (e[ed].data!=fa) del(e[ed].data,x,an);
        }
    } 
    void heave(int x, int fa){
        size[x]=1; mx[x]=0;
        for (int ed=head[x]; ed!=0; ed=e[ed].next)
            if (e[ed].data!=fa){
                heave(e[ed].data,x);
                size[x]=size[x]+size[e[ed].data];
                mx[x]=max(mx[x],size[e[ed].data]);
            }
        mx[x]=max(mx[x],tmp-size[x]);
    }
    void solve(int x, int fa){
        int cnt=0;
        for (int ed=head[x]; ed!=0; ed=e[ed].next)
            if (e[ed].data!=fa) solve(e[ed].data,x);
        for (int ed=head[x]; ed!=0; ed=e[ed].next)
            if (e[ed].data!=fa) now[++cnt]=h[e[ed].data];
        sort(now+1,now+cnt+1);
        h[x]=S;
        for (int i=1; i<=cnt; i++) h[x]=(h[x]*Q+now[i]+B)%P;
        h[x]=(h[x]*h[x])%P;
    }
    int main(){
        m=read();
        for (int t=1; t<=m; t++){
            n=read();
            memset(head,0,sizeof(head)); place=0;
            memset(deg,0,sizeof(deg));
            for (int i=1; i<n; i++){
                int u=read(), v=read();
                build(u,v), build(v,u);
                deg[u]++, deg[v]++; 
            }
            tmp=n;
            for (int i=1; i<=n; i++){
                if (deg[i]==1) rt=i;
                if (deg[i]==2) tmp--;
            }
            num=0; del(rt,0,0);
            memset(head,0,sizeof(head)); place=0;       
            for (int i=1; i<=num; i++){
                build(nexu[i],nexv[i]);
                build(nexv[i],nexu[i]);
            }
            heave(rt,0);
            int mn=inf, mnsize=0;
            for (int i=1; i<=n; i++){
                if (deg[i]==2) continue;
                if (mn>mx[i]) mn=mx[i], mnsize=0;
                if (mn==mx[i]) p[++mnsize]=i;
            }
            if (mnsize==2){
                memset(head,0,sizeof(head));
                for (int i=1; i<=num; i++){
                    if ((nexu[i]==p[1]&&nexv[i]==p[2])||(nexu[i]==p[2]&&nexv[i]==p[1])){
                        build(n+1,nexu[i]), build(nexu[i],n+1);
                        build(n+1,nexv[i]), build(nexv[i],n+1);
                    }
                    else {
                        build(nexu[i],nexv[i]);
                        build(nexv[i],nexu[i]);
                    }
                }
                rt=n+1;
            }
            else rt=p[1];
            solve(rt,0); 
            fin[t].num=tmp; fin[t].sum=h[rt];
        }
        sort(fin+1,fin+m+1,cmp);
        int cnt=0;
        for (int i=1; i<=m; i++)
            if (fin[i].sum!=fin[i-1].sum)
                size[++cnt]=fin[i].num;
        sort(size+1,size+cnt+1);
        printf("%d
    ",cnt);
        for (int i=1; i<=cnt; i++)
            printf("%d%c",size[i],(i==cnt)?('
    '):(' '));
        return 0;
    }
    
  • 相关阅读:
    SVN 初级教程
    572 node包管理工具
    571 node的events模块
    570 node内置模块fs
    569 node内置模块path
    568 node之JavaScript模块化:exports,module.exports,import,对象的引用赋值,require查找规则,export、import关键字,CommonJS的加载过程,ES Module加载过程
    567 node概述:Node程序传递参数,常见的全局对象,特殊的全局对象
    566 手写37个 原生JavaScript 系列汇总(含promise A+)
    565 手写promise源码
    564 函数的防抖和节流
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135947.html
Copyright © 2011-2022 走看看