jzoj 3957 鸡腿の花园

Description
【故事の背景】
 
鸡腿是CZYZ的著名DS,他为了树立高富帅的伟大形象决定暑假去张江大学学习(游玩)。张江大学自古以来就是充满了各种程序猿的地方,这里的花园自然也是十分奇葩,充满了符合程序猿口味的东西。鸡腿来到张江,自己也打理了一个小花园,小花园里种满了二叉树!
 
二叉树是什么呢,一棵树,除了根节点之外每个点都有父亲节点,同时每个节点只会有0个、1个或者2个孩子的树。
 
【问题の描述】
 
鸡腿在种树的过程中发现有两棵二叉树长的骨骼清奇,是树中极品。为了仔细研究这两颗树,鸡腿决定要研究一下这两棵树的共同点。鸡腿想让你帮他算一算,这两棵树上有多少相同的子树。
相同的子树指树A中的子树a和树B中的子树b完全相同,二叉树的相同定义为树上总节点个数相同,根节点孩子数相同,而且两棵子树分别相同。当然,孩子节点是有先后顺序的!
Data Constraint
对于20%的数据1 ≤ N,M ≤ 100;
对于40%的数据 1 ≤ N,M ≤ 5,000;
对于100%的数据 1 ≤ N,M ≤ 100,000。
 
Sol 

 Hash大法好。

 Hash函数随便写,怎么奇怪怎么来。

 

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
struct Hax{
    #define HaN 1234007
    int hea[HaN],net[HaN],fall[HaN],tot;
    ull key[HaN];
    int &get(ull _h){
        static int h;
        h=_h%HaN;
        for (int i=hea[h];i;i=net[i])
         if (key[i]==_h) return fall[i];
        key[++tot]=_h; net[tot]=hea[h]; hea[h]=tot;
        return fall[tot];
    }
    int Get(ull _h){
        static int h;
        h=_h%HaN;
        for (int i=hea[h];i;i=net[i])
         if (key[i]==_h) return fall[i];
        key[++tot]=_h; net[tot]=hea[h]; hea[h]=tot;
        return fall[tot];
    }
}f;
#define N 2000007
#define lx 23333
#define rx 998443
int siz[N],ch[N][2],n,m;
ull ha[N],ans;
void dfs(int x){
    if (ch[x][0]) dfs(ch[x][0]);
    if (ch[x][1]) dfs(ch[x][1]);
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    ha[x]=ha[ch[x][0]]*ha[ch[x][0]]*lx+ha[ch[x][1]]*rx+siz[x]^siz[ch[x][1]];
    f.get(ha[x])++;
}
void Dfs(int x){
    if (ch[x][0]) Dfs(ch[x][0]);
    if (ch[x][1]) Dfs(ch[x][1]);
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    ha[x]=ha[ch[x][0]]*ha[ch[x][0]]*lx+ha[ch[x][1]]*rx+siz[x]^siz[ch[x][1]];
    ans+=f.Get(ha[x]);
}
signed main () {
    freopen("1.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) {
     scanf("%d%d",ch[i],ch[i]+1); 
     if (ch[i][0]==-1) ch[i][0]=0;
     if (ch[i][1]==-1) ch[i][1]=0;
     }
    dfs(1);
    memset(ch,0,sizeof ch);
    memset(siz,0,sizeof siz);
    memset(ha,0,sizeof ha);
    for (int i=1;i<=m;i++) {
     scanf("%d%d",ch[i],ch[i]+1); 
     if (ch[i][0]==-1) ch[i][0]=0;
     if (ch[i][1]==-1) ch[i][1]=0;
     }
    Dfs(1);
    printf("%u\n",ans); 
    return 0;
}

 

转载于:https://www.cnblogs.com/rrsb/p/9318168.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值