zoukankan      html  css  js  c++  java
  • [NOI2020] 超现实树

    一、题目

    点此看题

    二、解法

    首先要简化问题,我一开始就是直接想怎么合并然后两个小时没有结果,虽然已经摸到了正解的门槛 (...)

    就想一下哪些树可能有用吧!如果直接考虑所有树的话太难了,可以大概感觉到最基本的树应该是一条链上面挂了叶子,这种结构我们称之为链树,链树是能生成许多树的状态的,但是是否有非链树的组合达到链树效果的情况呢?画下图呗:

    你仔细观察下就知道是不能等效的,因为链树只伸出去的叶子的情况会有无限多种,而这种情况在右边是没有的。所以说明了一个至关重要的结论:链树可以是生成无限树的基本树,并且非链树就算组合也不能等效链树

    那么可以抛弃掉非链树了,只考虑链树问题会简化很多。现在我们要考虑很多链树的并集,可以考虑用某种状态表示链树,使得合并之后的状态能够等效合并前两个链树状态的并集,状态不会很多,从链树的形态出发分类:

    • 状态 (1):只有左儿子
    • 状态 (2):只有右儿子
    • 状态 (3):有右儿子,左儿子是叶子
    • 状态 (4):有左儿子,右儿子是叶子

    那么可以把链树分类递归下去(每一个点都有一个状态),那么怎么定义状态是否合法呢?我们先固定上面递归下来的形态,在此基础上能生成无限多种树,由于我们定义的状态覆盖了所有情况,所以可以得到合法判定条件:

    • 这个状态对应点是叶子(可能不同数对应不同点,只要有其一是叶子即可)
    • 这个状态的四个子状态都合法

    那么类似线段树合并写一下就行了,时间复杂度 (O(sum n))

    总结一下,本题主要用到的思想是:简化问题(这一点很重要我没想到);合并思想、等效思想(把一堆东西的组合等效单个东西);定义状态(其实就找到了递归子问题)

    #include <cstdio>
    const int M = 2000005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,m,rt,cnt,ch[M][4],c[M],ls[M],rs[M];
    int chk(int x)//判断是否是叶子 
    {
    	return !ls[x]&&!rs[x];
    }
    int pd(int x)
    {
    	if(chk(x) || (!rs[x] && pd(ls[x])) || (!ls[x] && pd(rs[x])))
    		return 1;
    	return (chk(rs[x]) && pd(ls[x])) || (chk(ls[x]) && pd(rs[x]));
    }
    void merge(int &x,int y)
    {
    	if(!x) x=++cnt;
    	if(chk(y))
    	{
    		c[x]=1;
    		return ;
    	}
    	if(!rs[y]) merge(ch[x][0],ls[y]);
    	if(!ls[y]) merge(ch[x][1],rs[y]);
    	if(ls[y] && rs[y] && chk(ls[y])) merge(ch[x][2],rs[y]);
    	if(ls[y] && rs[y] && chk(rs[y])) merge(ch[x][3],ls[y]);
    }
    int grow(int x)
    {
    	if(!x||c[x]) return x>0;
    	return grow(ch[x][0]) && grow(ch[x][1])
    	&& grow(ch[x][2]) && grow(ch[x][3]);
    }
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		m=read();
    		cnt=rt=0;
    		while(m--)
    		{
    			n=read();
    			for(int i=1;i<=n;i++)
    				ls[i]=read(),rs[i]=read();
    			if(pd(1)) merge(rt,1);
    		}
    		if(grow(rt)) puts("Almost Complete");
    		else puts("No");
    		for(int i=1;i<=cnt;i++)
    			for(int j=0;j<4;j++)
    				ch[i][j]=c[i]=0;
    	}
    }
    
  • 相关阅读:
    Decision Tree、Random Forest、AdaBoost、GBDT
    正则化:L0 vs L1 vs L2
    处理不平衡数据的基本方法
    常用的评价指标:accuracy、precision、recall、f1-score、ROC-AUC、PR-AUC
    创建以mybatis为基础的web项目(1)
    [.Net] C# Excel操作类 ExcelHelper
    [.Net] C#开发微信门户及应用之微信菜单的多种表现方式介绍
    [.Net] Excel导入导出各种方式分析
    [Javascript] 轻量级的JavaScript日期处理类库xDate使用指南
    [Javascript] 40个轻量级JavaScript脚本库
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14656803.html
Copyright © 2011-2022 走看看