传送门: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);
}
}