P6776-[NOI2020]超现实树

1|0正题

题目链接:https://www.luogu.com.cn/problem/P6776


1|1题目大意

定义一次操作为将一棵树的叶子换成另一棵树。
定义一棵树Tgrow(T)表示所有树T能够通过操作变成的树的集合。

现在给出m棵树Ti,定义S为所有grow(Ti)的交集。

S是否几乎完备(指仅有有限棵树不在集合S内)。

1n,m2×106,T100


1|2解题思路

我们考虑所有的树(因为我们要细分到子树考虑所以这里考虑上空树)中,一个点可以到达所有非空树,其他非空树都不能到达一个点,而空树和一个点不能相互到达。

我们先把所有读入的树并起来,然后每到一个点就分别考虑左右两边是否完备。

如果所有的树都存在一个点x使得左右两边都至少有两个点,那么这棵树就没有作用了,因为某一边一个点或者空树它们都到达不了,那另一边就可以随便排了。

所以对于每个位置我们要保证左/右边为0个点和左/右边为1为一个点的树中,在另一边都要是几乎完备的就合法了。

时间复杂度:O(n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cctype> #define mp(x,y) make_pair(x,y) #define ull unsigned long long using namespace std; const int N=2e6+10; const ull g=131; struct node{ int id,x; node(int iid,int xx) {id=iid;x=xx;return;} }; const int o[2]={0,0}; int Case,n,m,cnt,t[N][2],siz[N]; ull pw[N];vector<node>q[N]; int read(){ int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-f;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*f; } struct Tree{ vector<int> ch[2]; vector<int> siz; void build(int &x,int p){ if(!x)x=++cnt; if(ch[0][p])build(t[x][0],ch[0][p]); if(ch[1][p])build(t[x][1],ch[1][p]); siz[p]=1+siz[ch[0][p]]+siz[ch[1][p]]; return; } void init(int p){ n=read();siz.resize(n+1); ch[0].resize(n+1); ch[1].resize(n+1); for(int i=1;i<=n;i++) ch[0][i]=read(),ch[1][i]=read(); int rt=1;build(rt,1); q[1].push_back(node(p,1)); } void Clear() {ch[0].clear();ch[1].clear();siz.clear();} bool isSon(int x){return (!ch[0][x]&&!ch[1][x]);} }T[N]; bool solve(int x){ for(int i=0;i<q[x].size();i++) if(T[q[x][i].id].isSon(q[x][i].x))return 1; if(!q[x].size()||!t[x][0]||!t[x][1])return 0; bool ans=1; for(int i=0;i<q[x].size();i++){ int id=q[x][i].id,y=q[x][i].x; if(T[id].siz[T[id].ch[1][y]]==0&&T[id].ch[0][y]) q[t[x][0]].push_back(node(id,T[id].ch[0][y])); } ans&=solve(t[x][0]); q[t[x][0]].clear(); for(int i=0;i<q[x].size();i++){ int id=q[x][i].id,y=q[x][i].x; if(T[id].siz[T[id].ch[1][y]]==1&&T[id].ch[0][y]) q[t[x][0]].push_back(node(id,T[id].ch[0][y])); } ans&=solve(t[x][0]); q[t[x][0]].clear(); for(int i=0;i<q[x].size();i++){ int id=q[x][i].id,y=q[x][i].x; if(T[id].siz[T[id].ch[0][y]]==0&&T[id].ch[1][y]) q[t[x][1]].push_back(node(id,T[id].ch[1][y])); } ans&=solve(t[x][1]); q[t[x][1]].clear(); for(int i=0;i<q[x].size();i++){ int id=q[x][i].id,y=q[x][i].x; if(T[id].siz[T[id].ch[0][y]]==1&&T[id].ch[1][y]) q[t[x][1]].push_back(node(id,T[id].ch[1][y])); } ans&=solve(t[x][1]); q[t[x][1]].clear(); return ans; } int main() { // freopen("surreal4.in","r",stdin); scanf("%d",&Case);pw[0]=1; for(int i=1;i<N;i++)pw[i]=pw[i-1]*g; while(Case--){ for(int i=1;i<=cnt;i++)q[i].clear(),t[i][0]=t[i][1]=0; for(int i=1;i<=m;i++)T[i].Clear(); cnt=1;m=read(); for(int p=1;p<=m;p++) T[p].init(p); if(solve(1))puts("Almost Complete"); else puts("No"); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16420061.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-06-28 P3964-[TJOI2013]松鼠聚会【计算几何】
2021-06-28 AT2667-[AGC017D]Game on Tree【SG函数】
2021-06-28 P5163-WD与地图【tarjan,整体二分,线段树合并】
点击右上角即可分享
微信分享提示