[loj3343]超现实树
定义1:两棵树中的$x$和$y$对应当且仅当$x$到根的链与$y$到根的链同构
定义2:$x$和$y$的儿子状态相同当且仅当$x$与儿子所构成的树与$y$与儿子所构成的树同构
根据题中所给的定义,有以下两个的结论(观察可得,证明略):
结论1:对于两棵树$T_{1}$和$T_{2}$,$T_{1}->T_{2}$当且仅当对于$T_{1}$中的非叶子节点$x$和$T_{2}$中对应的点$y$,$x$和$y$的儿子状态相同
结论2:$grow(\mathscr{T})$几乎完备当且仅当不存在一棵树$T'$使得$\max h<h(T')$且$\forall 1\le i\le n,T_{i}\ne >T'$
这两个结论都比较显然,考虑继续发掘一些更有用的结论——
定义3:$T$为“链树”当且仅当其存在一条由根到某个叶子的链,使得树上任意一点到链上最近的点距离不超过1
结论3:对于树$T_{1}$和链树$T_{2}$,$T_{1}->T_{2}$当且仅当$T_{1}$为链树且$T_{2}$中所有深度不超过$h(T_{1})$的点所组成的树与$T_{1}$同构
(这个就是结论1通过观察得到的推论,即要求$T_{1}$是$T_{2}$的一个“前缀”(不太严谨),证明略)
结论4:$grow(\mathscr{T})$几乎完备当且仅当不存在一棵“链树”$T'$使得$\max h<h(T')$且$\forall 1\le i\le n,T_{i}\ne >T'$
证明:观察到仅将树改为了“链树”,由于“链树”的必要条件是树,结论2即必要性
考虑充分性,构造:对于一棵符合条件的树$T'$,将$T'$中最深的点(多个任选一个)到根的链作为$T''$的那条链,保留$T''$中所有到这条链距离为1的点(删去其他点),所构成的树显然为“链树”,接下去证明其符合条件
由于最长的链被保留,因此$\max h<h(T')=h(T'')$
由于$\forall 1\le i\le n,T_{i}\ne >T'$,必然有非叶子节点$x$使得$x$和$T'$中对应的点$y$儿子状态不同,令$a_{i}=y$
1.若$a_{i}$在链上(指“链树”的链),未改变$a_{i}$的儿子状态,仍然符合条件;
2.若$a_{i}$到链上最近的点距离为1,其儿子一定不被保留,则其为叶子节点而$x$为非叶子节点,儿子状态不同;
3.若$a_{i}$不被保留,取$a_{i}$为最近的被保留的祖先$z$,不妨设$a_{i}$在$z$的左子树中,由于$T_{i}$中存在$x$因此$z$在$T_{i}$中对应的点有左子树,而现在$z$的左子树必然为空(否则$z$应该取左儿子),即儿子状态不同
根据这两个结论,可以删去所有不为“链树”的树,然后暴力枚举链树:分为4类,链在(左/右)子树,有无(右/左)儿子,并递归链所在的子树
枚举时,维护一个$vector$表示当前仍然合法(即设枚举到的链树为$T'$,$T_{i}$合法当且仅当$T'->T_{i}$)的“链树”,同时若满足了$T_{i}->T'$(即当前决定儿子状态的点在$T_{i}$中对应的点为叶子)就停止枚举
考虑这一做法的时间复杂度:
当一棵“链树”最深的节点有兄弟,此时不妨视为两棵,这就保证每一棵链树仅被分入4类中的一类
时间复杂度即所有“链树”被划分的次数之和,而每一次划分可以看作“删除”掉当前正在处理的节点,显然这些删除不会重复,因此划分即删除的次数不超过$o(n)$,总复杂度即为$o(n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2000005 4 vector<int>v[N]; 5 int V,T,t,n,m,r[N],ls[N],rs[N],tot[N]; 6 bool pd(int k){ 7 if (!tot[k])return 1; 8 if ((!tot[rs[k]])&&(pd(ls[k])))return 1; 9 if ((!tot[ls[k]])&&(pd(rs[k])))return 1; 10 return 0; 11 } 12 bool dfs(){ 13 bool v0=0,v1=0,v2=0,v3=0; 14 for(int i=0;i<v[T].size();i++){ 15 if (!tot[v[T][i]])return 0; 16 if ((ls[v[T][i]])&&(!tot[rs[v[T][i]]])&&(rs[v[T][i]]))v0=1; 17 if ((ls[v[T][i]])&&(!tot[ls[v[T][i]]])&&(ls[v[T][i]]))v1=1; 18 if ((rs[v[T][i]])&&(!tot[rs[v[T][i]]])&&(rs[v[T][i]]))v2=1; 19 if ((rs[v[T][i]])&&(!tot[ls[v[T][i]]])&&(ls[v[T][i]]))v3=1; 20 } 21 if ((!v0)||(!v1)||(!v2)||(!v3))return 1; 22 v[T+1].clear(); 23 for(int i=0;i<v[T].size();i++) 24 if ((ls[v[T][i]])&&(!tot[rs[v[T][i]]])&&(rs[v[T][i]]))v[T+1].push_back(ls[v[T][i]]); 25 T++; 26 if (dfs())return 1; 27 T--; 28 v[T+1].clear(); 29 for(int i=0;i<v[T].size();i++) 30 if ((ls[v[T][i]])&&(!tot[rs[v[T][i]]])&&(!rs[v[T][i]]))v[T+1].push_back(ls[v[T][i]]); 31 T++; 32 if (dfs())return 1; 33 T--; 34 v[T+1].clear(); 35 for(int i=0;i<v[T].size();i++) 36 if ((rs[v[T][i]])&&(!tot[ls[v[T][i]]])&&(ls[v[T][i]]))v[T+1].push_back(rs[v[T][i]]); 37 T++; 38 if (dfs())return 1; 39 T--; 40 v[T+1].clear(); 41 for(int i=0;i<v[T].size();i++) 42 if ((rs[v[T][i]])&&(!tot[ls[v[T][i]]])&&(!ls[v[T][i]]))v[T+1].push_back(rs[v[T][i]]); 43 T++; 44 if (dfs())return 1; 45 T--; 46 return 0; 47 } 48 int main(){ 49 freopen("surreal.in","r",stdin); 50 freopen("surreal.out","w",stdout); 51 scanf("%d",&t); 52 while (t--){ 53 scanf("%d",&m); 54 V=0; 55 for(int i=1;i<=m;i++){ 56 scanf("%d",&n); 57 r[i]=V+1; 58 for(int j=1;j<=n;j++){ 59 scanf("%d%d",&ls[j+V],&rs[j+V]); 60 if (ls[j+V])ls[j+V]+=V; 61 if (rs[j+V])rs[j+V]+=V; 62 tot[j+V]=(ls[j+V]>0)+(rs[j+V]>0); 63 } 64 V+=n; 65 if (!pd(r[i])){ 66 V-=n; 67 i--; 68 m--; 69 } 70 } 71 T=0; 72 v[0].clear(); 73 for(int i=1;i<=m;i++)v[0].push_back(r[i]); 74 if (dfs())printf("No\n"); 75 else printf("Almost Complete\n"); 76 } 77 return 0; 78 }