山理工校赛 E.bLue的二叉树 dfs序+字符串匹配(KMP、哈希)

7 篇文章 0 订阅

传送门:bLue的二叉树

思路:求第一棵树的子树有多少个和第二棵树相同,刚看题的时候还看错了,以为是两棵树的子树有多少个相同的,想都没想就写了个哈希,写完发现好像不太对,我是在dfs的过程中哈希的,但是连样例都过不了,就开始怀疑自己是不是子树的定义搞错了。。然后就凌乱了。。

正解:将两棵树按dfs序做成字符串,注意空节点也要用一个不会出现在其他节点的值加到字符串当中。做出字符串来后再做个字符串匹配就好了。。

至于为什么能这么做,我自己认为的是一个包含空节点的先序序列能惟一的确定一颗二叉树,把空节点加到串中也能避免出现两个子树的序列连起来恰好形成了待匹配的序列的情况。

据说直接对子树哈希也能过,不过姿势要好,看来是我姿势太差劲了。。连样例都过不了。。

还据说搜索+强剪枝也能过。。

代码(哈希求的字符串匹配):

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100007
#define ll long long
#define ull unsigned long long
const ull P=1e9+7;
vector<int>a[MAXN],b[MAXN];
int c1[MAXN],c2[MAXN];
int in[MAXN];
int n,m;
string w1,w2;
void dfs1(int u)
{
	if(!u)
	{
		w1+='A';
		return ;
	}
    for(int i=0;i<a[u].size();i++)
    {
        int v=a[u][i];
        dfs1(v);
    }
    w1+=(c1[u]+'A');
    return ;
}
void dfs2(int u)
{
	if(!u)
	{
		w2+='A';
		return ;
	}
    for(int i=0;i<b[u].size();i++)
    {
        int v=b[u][i];
        dfs2(v);
    }
    w2+=(c2[u]+'A');
    return ;
}
int main()
{
    int w,l,r;
    while(~scanf("%d%d",&n,&m))
    {
        w1="";
        w2="";
        for(int i=0;i<MAXN;i++)
        {
            a[i].clear();
            b[i].clear();
            in[i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&c1[i],&l,&r);
            //if(l!=0)
            a[i].push_back(l),in[l]++;
            //if(r!=0)
            a[i].push_back(r),in[r]++;
        }
        int rt1,rt2;
        for(int i=1;i<=n;i++)
        if(in[i]==0)
        {
            rt1=i;
            break;
        }
        memset(in,0,sizeof(in));
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&c2[i],&l,&r);
            //if(l!=0)
            b[i].push_back(l),in[l]++;
            //if(r!=0)
            b[i].push_back(r),in[r]++;
        }
        for(int i=1;i<=m;i++)
        if(in[i]==0)
        {
            rt2=i;
            break;
        }
        ll ans=0;
        dfs1(rt1);
        dfs2(rt2);
        //cout<<w1<<endl<<w2<<endl;
        ull T=0,S=0,xx=1;
        for(int i=0;i<w2.size();i++)
        {
        	xx*=P;
        	T=w2[i]+T*P;
        	S=w1[i]+S*P;
		}
		if(S==T)
		ans++;
		int sz=w2.size();
		for(int i=sz;i<w1.size();i++)
		{
			S=S*P+w1[i]-w1[i-sz]*xx;
			if(S==T)
			ans++;
		}
        printf("%lld\n",ans);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值