Description
LOJ3343
判断一个可以叶子可以生长的树的集合是否几乎完备
n
,
m
≤
2
e
6
n,m\le2e6
n,m≤2e6
Solution
一道性质题。考场上的时候想到了一些根据树的形态进行trie上dfs的方式去分治的做法,但是过于复杂,也并没有实现。我并没有意识到一个重要的性质:所有的树都可以由若干种树枝(每一个点的儿子的最小大小不超过1,即一个链在某些节点外挂一个点)生长出来,所以如果只有有限个树枝不能得到,意味着也只有有限个树不能得到。也就是,树枝是一个树的基底,如果几乎所有基底都有,那么也几乎所有树都能表示了。接下来就很简单了。首先只有原本是树枝的树能组成树枝,考虑这些要组成几乎所有树枝,那么就考虑存在一个点没有儿子,或剩下两个儿子的大小为>=1或=1,一共四种情况递归下去都分别几乎完备,那么这个点就是完备的。dfs即可。
O
(
n
)
O(n)
O(n)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 2000005
using namespace std
;
int T
,m
,i
,j
,k
,tot
,n
,t
[maxn
][2],sz
[maxn
],rt
[maxn
],f
[maxn
];
vector
<int> d
[maxn
];
void read(int &x
){
x
=0; char ch
=getchar();
for(;ch
<'0'||ch
>'9';ch
=getchar());
for(;ch
>='0'&&ch
<='9';ch
=getchar()) x
=x
*10+ch
-'0';
}
int getsz(int x
){
sz
[x
]=1,f
[x
]=0;
if (t
[x
][0]) sz
[x
]+=getsz(t
[x
][0]),f
[x
]=max(f
[x
],f
[t
[x
][0]]);
if (t
[x
][1]) sz
[x
]+=getsz(t
[x
][1]),f
[x
]=max(f
[x
],f
[t
[x
][1]]);
f
[x
]=max(f
[x
],min(sz
[t
[x
][0]],sz
[t
[x
][1]]));
return sz
[x
];
}
int check(int k
){
if (!d
[k
].size()) return 0;
for(int i
=0;i
<d
[k
].size();i
++) if (!t
[d
[k
][i
]][0]&&!t
[d
[k
][i
]][1]) return 1;
d
[k
+1].clear();
for(int i
=0;i
<d
[k
].size();i
++) if (t
[d
[k
][i
]][0]&&sz
[t
[d
[k
][i
]][1]]==1)
d
[k
+1].push_back(t
[d
[k
][i
]][0]);
if (!check(k
+1)) return 0;
d
[k
+1].clear();
for(int i
=0;i
<d
[k
].size();i
++) if (t
[d
[k
][i
]][1]&&sz
[t
[d
[k
][i
]][0]]==1)
d
[k
+1].push_back(t
[d
[k
][i
]][1]);
if (!check(k
+1)) return 0;
d
[k
+1].clear();
for(int i
=0;i
<d
[k
].size();i
++) if (t
[d
[k
][i
]][0]&&!t
[d
[k
][i
]][1])
d
[k
+1].push_back(t
[d
[k
][i
]][0]);
if (!check(k
+1)) return 0;
d
[k
+1].clear();
for(int i
=0;i
<d
[k
].size();i
++) if (t
[d
[k
][i
]][1]&&!t
[d
[k
][i
]][0])
d
[k
+1].push_back(t
[d
[k
][i
]][1]);
if (!check(k
+1)) return 0;
return 1;
}
int main(){
freopen("ceshi.in","r",stdin);
read(T
);
while (T
--){
tot
=0,read(m
);
for(i
=1;i
<=m
;i
++){
read(n
),rt
[i
]=tot
+1;
for(j
=1;j
<=n
;j
++) {
read(t
[tot
+j
][0]),read(t
[tot
+j
][1]);
if (t
[tot
+j
][0]) t
[tot
+j
][0]+=tot
;
if (t
[tot
+j
][1]) t
[tot
+j
][1]+=tot
;
} tot
+=n
;
}
for(i
=1;i
<=m
;i
++) getsz(rt
[i
]);
d
[1].clear();
for(i
=1;i
<=m
;i
++) if (f
[rt
[i
]]<=1) d
[1].push_back(rt
[i
]);
if (check(1)) printf("Almost Complete\n");
else printf("No\n");
}
}