ZOJ3965 给定一颗二叉树的两种DFS序列 输出一种可能的二叉树的结构。
考察树的递归性质,不要想的太复杂。
当前节点在两个串中后面的节点假如不同则能确认两个子树,如果相同则把下个点作当前点的一个儿子。如果子树中还有未连根的点则接到当前点下。son数组表示每个点的子树有多少个点。pos数组记录每个数在每个序列中的位置。dfs中p1,p2指向同一个数
lim1,lim2表示当前点子树可能最大的子树范围。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<vector> using namespace std; #define maxn 110000 int n,fa[maxn]; int s1[maxn],s2[maxn]; int pos1[maxn],pos2[maxn]; int vis[maxn],son[maxn]; void dfs(int p1,int p2,int lim1,int lim2) { //printf("%d %d %d %d ::::: ",p1,lim1,p2,lim2); //system("pause"); int now=s1[p1]; if(vis[now]) return; vis[now]=1; if(p1<=0||p1>n) return ; if(p2<=0||p2>n) return ; if(lim1<=0) return ; if(lim2<=0) return ; if(p1>lim1||p2>lim2) return; son[now]=1; if(lim1==p1||lim2==p2) return; int r1=lim1,r2=lim2; if(s1[p1+1]!=s2[p2+1]&&p1+1<=lim1&&p2+1<=lim2) { int len=0; if(!fa[s1[p1+1]]) { fa[s1[p1+1]]=now; r1=pos1[s2[p2+1]]-1; len=r1-p1; dfs(p1+1, pos2[ s1[p1+1] ] , r1 ,pos2[ s1[p1+1] ]+len-1 ); son[now]+=son[ s1 [p1+1] ]; } if(!fa[s2[p2+1]]) { fa[s2[p2+1]]=now; r2=pos2[s1[p1+1]]-1; len=r2-p2; dfs( pos1[s2[p2+1]] , p2+1, pos1[s2[p2+1]]+len-1, r2 ); son[now]+=son[ s2 [p2+1] ]; } } else if(s1[p1+1]==s2[p2+1]&&p1+1<=lim1&&p2+1<=lim2) { fa[ s1[p1+1] ] = now; dfs(p1+1,p2+1,lim1,lim2); son[now]+=son[ s1[p1+1] ]; int nt=p1+son[s1[p1+1]]+1; if(son[now]<lim1-p1+1) { fa[s1[nt]]=now; dfs(nt,pos2[s1[nt]],lim1,lim2); son[now]+=son[s1[nt]]; } } } int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d",&n); memset(fa,0,sizeof(fa)); memset(vis,0,sizeof(vis)); memset(son,0,sizeof(son)); memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2)); memset(pos1,0,sizeof(pos1)); memset(pos2,0,sizeof(pos2)); for(int i=1;i<=n;i++) scanf("%d",&s1[i]),pos1[s1[i]]=i; for(int i=1;i<=n;i++) scanf("%d",&s2[i]),pos2[s2[i]]=i; dfs(1,1,n,n); for(int i=1;i<n;i++) printf("%d ",fa[i]); printf("%d ",fa[n]); } return 0; }