题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2176/pid/3926.html
——————————————————————————————————————
bLue的二叉树
Time Limit: 3000MS Memory Limit: 65536KB
Submit Statistic
Problem Description
Keke 是一个喜爱种树的人,他对各种树都有很深的研究。
MLE 听说 bLue 种了一些新品种的树,就想邀请 Keke 去围观一下。
PBH 在暗中把这一切尽收眼底,作为资深植树行家,他虽不屑,但也决定和他们一起去看一看。
于是,大家便一起到了 bLue 家去看树。
bLue 有两棵二叉树,分别有 n 和 m 个节点,编号分别为 1-n 和 1-m,每个节点都有一个权值,bLue 想知道第一棵树的所有子树中与第二棵树完全相同的个数(不考虑节点编号)。
Input
输入数据有多组,组数不超过 150,到 EOF 结束。
每组第一行有两个整数 n (0 < n <= 1e5)和 m (0 < m <= 1e5),表示第一棵树和第二棵树的节点个数;
接下来 n 行,表示第一棵树:第 i (0 < i <= n) 行有 3 个整数,w[i] (0 < w[i] <= 10), lc[i], rc[i] (0 < lc[i], rc[i] <= n),分别表示节点 i 的权值,该节点的左孩子编号和右孩子编号,若某个孩子不存在,则为 0 (数据保证每棵树都是合法的有根二叉树);
接下来 m 行,表示第二棵树:格式同第一棵树;
保证:树的最大深度不会超过 10000。数据量比较大,请用 scanf 读入!
Output
对于每组数据,输出一行一个整数 num,表示第一棵树的所有子树中与第二棵树完全相同的个数。
Example Input
7 4
1 6 3
2 0 4
1 7 0
3 0 0
1 2 1
2 0 0
2 0 0
2 0 0
1 4 0
1 1 2
2 0 0
3 3
1 0 0
2 1 3
3 0 0
1 0 3
2 1 0
3 0 0
Example Output
1
0
Hint
Author
不得不放弃、
——————————————————————————————————————
首先确定的是严格确定 二叉树的左子树和左子树对 上右子树和右子树对上才行
对于子树问题考虑dfs序
对于一个dfs序,区间内的东西都是子树的,那么对于两个完全一样的子树.遍历出来的区间也是一模一样的.
但是为了避免有多个子树遍出结果一样的,我们只需把空节点当作一个不一样的权值加入到树中,这样既能确保区间序列一样,同时又不会冲突.
最后对两个dfs序KMP即能求解
其实这题是能够hash做的 ,最开始我也在想hash的方法,但是想不到怎么处理左右儿子的左/右儿子到底在那,所以不太行,,== 现在想到对dfs序后他的位置l的x^l的系数 感觉很可行啊 ,同时也要做dfs==! 其实还是字符串hash了,,,,,
附本题两份KMP+hash代码
——————————————————————————————————————
#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;
#define abs(x) (((x)>0)?(x):-(x))
const int N = 1e5+10;
const int MOD = 1e9+7;
int sum;
LL read(){
LL x=0;char ch=getchar();
while('0'>ch||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';sum++;ch=getchar();}
return x;
}
/******************************************/
int n,m;
int a[N][3],b[N][3],c[N<<1],d[N<<1],lc,ld;
void dfs1(int rt){
c[lc++]=a[rt][0];//printf("%d ",a[rt][0]);
if(rt==0) return;
dfs1(a[rt][1]);
dfs1(a[rt][2]);
}
void dfs2(int rt){
d[ld++]=b[rt][0];//printf("%d ",b[rt][0]);
if(rt==0) return;
dfs2(b[rt][1]);
dfs2(b[rt][2]);
}
int Next[N<<1];//Next[i] 表示从[0~i]中最长公共前缀的长.
void get_next(int *s,int len){
for(int i=0,j=-1;i<=len;++i,++j){
Next[i]=j;
while(j>=0&&s[i]!=s[j]) j = Next[j];
}
// for(int i=0;i<=len;i++) printf("%d%c",Next[i],(i==len)?'\n':' ');
}
//在串s上找sz
int KMP (int *s,int len,int *sz,int l){
int i=0,j=0,cnt=0;
while(i<len/*&&j<l*/){
if(s[i]==sz[j]) i++,j++;
else{
if(0==j) i++;
else j=Next[j];
}
if(j==l) cnt++;
}
// return (j==l)?(i-l+1):-1; //找第一次出现的位置
return cnt; //找出现的个数
}
bool visa[N],visb[N];
int main(){
while(~scanf("%d%d",&n,&m)){
lc=ld=0;
for(int i=1;i<=n;i++) a[i][0]=read(),a[i][1]=read(),a[i][2]=read(),visa[a[i][1]]=visa[a[i][2]]=1;
for(int i=1;i<=m;i++) b[i][0]=read(),b[i][1]=read(),b[i][2]=read(),visb[b[i][1]]=visb[b[i][2]]=1;
for(int i=1;i<=n;i++) if(visa[i]==0){dfs1(i);break;}//puts("");
for(int i=1;i<=m;i++) if(visb[i]==0){dfs2(i);break;}//puts("");
get_next(d,ld);
printf("%d\n",KMP(c,lc,d,ld));
for(int i=1;i<=n;i++) visa[i]=0;
for(int i=1;i<=m;i++) visb[i]=0;
}
return 0;
}
/***************************************************
User name: tabris
Result: Accepted
Take time: 872ms
Take Memory: 596KB
Submit time: 2017-06-05 00:39:32
****************************************************/
#include <bits/stdc++.h>
typedef unsigned long long int LL;
using namespace std;
#define abs(x) (((x)>0)?(x):-(x))
const int N = 1e5+10;
const int MOD = 1e9+7;
int sum;
LL read(){
LL x=0;char ch=getchar();
while('0'>ch||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';sum++;ch=getchar();}
return x;
}
/******************************************/
int n,m,ans,lc,ld;
int a[N][3],b[N][3];//,lb[N],rb[N];
LL c[N<<1],x,h,tota,totb;
void dfs1(int rt){
++lc;
c[lc]=a[rt][0]*x;x*=h;
if(rt==0) return;
dfs1(a[rt][1]);
dfs1(a[rt][2]);
}
void dfs2(int rt){
++ld;
totb+=b[rt][0]*x;x*=h;
if(rt==0) return;
dfs2(b[rt][1]);
dfs2(b[rt][2]);
}
bool visa[N],visb[N];
int main(){
a[0][0]=b[0][0]=101;h=27;c[0]=0;
while(~scanf("%d%d",&n,&m)){
lc=ld=0;ans=0;tota=totb=0;
for(int i=1;i<=n;i++) a[i][0]=read(),a[i][1]=read(),a[i][2]=read(),visa[a[i][1]]=visa[a[i][2]]=1;
for(int i=1;i<=m;i++) b[i][0]=read(),b[i][1]=read(),b[i][2]=read(),visb[b[i][1]]=visb[b[i][2]]=1;
x=1;for(int i=1;i<=n;i++) if(visa[i]==0){dfs1(i);break;}//puts("");
x=1;for(int i=1;i<=m;i++) if(visb[i]==0){dfs2(i);break;}//puts("");
for(int i=1;i<ld;i++) tota+=c[i];
for(int i=ld;i<=lc;i++){
tota-=c[i-ld],tota+=c[i];
if(tota==totb) ans++;
totb*=h;
}
printf("%d\n",ans);
for(int i=1;i<=n;i++) visa[i]=0;
for(int i=1;i<=m;i++) visb[i]=0;
}
return 0;
}
/***************************************************
User name: tabris
Result: Accepted
Take time: 884ms
Take Memory: 2244KB
Submit time: 2017-06-05 01:34:54
****************************************************/