LOJ#3343.【NOI2020】超现实树(surreal)

tech2024-10-03  18

Description

LOJ3343

判断一个可以叶子可以生长的树的集合是否几乎完备 n , m ≤ 2 e 6 n,m\le2e6 n,m2e6

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); // freopen("surreal.in","r",stdin); // freopen("surreal.out","w",stdout); 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"); } }
最新回复(0)