【牛客】 寒假训练营3 K-智乃的“黑红树” 题解

本文介绍了一种特殊的“黑红树”构造方法,其中节点满足特定的着色规则。通过分析,确定了奇数黑节点和偶数红节点的必要性,并利用时间戳dfn进行节点标记,最终设计出O(n)的时间复杂度算法。文章还提供了C++代码实现。
摘要由CSDN通过智能技术生成

传送门:智乃的“黑红树”
标签:构造

题目大意

智乃有一颗"黑红树",“黑红树"是这样定义的:
1、“黑红树"中黑色节点的直接孩子为红色节点、红色节点的直接孩子为黑色节点。
2、“黑红树"是一颗以1号节点为根节点的二叉树,且根节点的颜色为黑色。
3、对于"黑红树"上任意一个节点,要么同时存在两个子节点,要么为叶节点不存在孩子。
现在智乃想要构造一颗根节点为1,树尺寸为N,节点编号从1到N的"黑红树”,该"黑红树”“恰好有a个黑点和b个红点,请你帮助她构造任意满足条件的"黑红树”,或者告诉她不存在任何满足条件的"黑红树”。
输入:T组数据,每组数据两个正整数n,m,分别代表黑红树中黑节点和红节点的数量。
输出:存在这样的黑红树则输出”Yes“,否则输出”No“。

算法分析

  • 首先我们知道红黑树是什么,但智乃的黑红树略有不同。他要求二叉树中的节点要么有两个节点要么有两个孩子要么为叶子节点。那么显然n必须为奇数,m必须为偶数,因为第一层的根节点为黑节点。我们自然会想到一种最简单的构造方法,就是奇数层排满黑节点,偶数层排满红节点,直到最后一层。
  • 这里引入完全二叉树的概念。大家都知道满二叉树,而完全二叉树就是除最后一层外为满二叉树,且最后一层的节点全部靠左侧。如果按照我们刚才说的构造方法,就会近似得到一棵完全二叉树,如果造不出来就说明无解。但这种方法是不是最优的还有待考虑。我们假设n=3,m=4,就会发现第一到四层的节点数量分别为:1,2,2,2,显然不是一棵完全二叉树,那么就证伪了。
  • 虽然最简单的方法行不通,但我们也发现了一个关键的信息:“黑红树”除去最后一层必为完全二叉树。也就是说只要稍微修改一下策略就能通过本题。构造完全二叉树时我们会想到编号为i的节点的子节点编号一定为2i和2i+1,因为只有排满了上一层才会有下一层。但是在本题中没有此规律,所以我们要采用时间戳dfn来为节点标号。
  • 定义一个f数组,初始化为-1,当为0时表示当前节点在奇数层,当为1时表示当前节点在偶数层。最初令f[1]=0,然后从1到n+m遍历i,如果当前节点f值为-1说明它不是根节点且没有父节点,直接输出No。如果当前节点在奇数层且m大于0,就可以在它下面挂两个红节点,并将这两个节点的f值更新为1。如果当前节点在偶数层且n大于0,就可以在它下面挂两个黑节点,并将这两个节点的f值更新为0。该算法总体时间复杂度为O(n)。

代码实现

#include <iostream>
using namespace std;
int dfn;
int l[200005],r[200005],f[200005];
#define lowbit(x) (x)&(-x)
int main(){
	long long dx,dy,p,q,i,j,x,y,x1,y1,n,m,T,sum,mx;
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n>>m;
        sum=n+m;
        if(n%2==0||m%2==1){cout<<"No\n";continue;}
        for(i=1;i<=n+m+1;i++)l[i]=r[i]=f[i]=-1;
        f[1]=0;dfn=1;n--;
        for(i=1;i<=sum;i++){
            if(f[i]==-1){
                cout<<"No\n";
                goto abc;
            }
            if(f[i]==0&&m){
                l[i]=++dfn;f[dfn]=1;
                r[i]=++dfn;f[dfn]=1;
                m-=2;
            }
            if(f[i]==1&&n){
                l[i]=++dfn;f[dfn]=0;
                r[i]=++dfn;f[dfn]=0;
                n-=2;
            }
        }
        cout<<"Yes\n";
        for(i=1;i<=sum;i++)
            cout<<l[i]<<' '<<r[i]<<'\n';
        abc:;
	}
	return 0;
}

vruntime黑红是一种用于进程调度的数据结构,它的设计目的是为了提高多任务操作系统中进程调度的效率和准确性。下面是关于vruntime黑红的回答: vruntime是指虚拟运行时间,在进程调度中用于衡量进程的优先级高低。而黑红是一种自平衡的二叉搜索,它通过对节点的颜色进行调整以保持的平衡。vruntime黑红将进程的vruntime值作为节点的键值,通过黑红的自平衡特性,可以快速地找到最小vruntime值的进程进行调度。 在vruntime黑红中,每个节点表示一个进程,节点的vruntime值用于比较进程的优先级。中的节点按照vruntime值从小到大排列,即的最左侧节点的vruntime值最小。通过对黑红进行旋转、颜色调整等操作,可以快速地插入新的进程节点,并找到最小vruntime值的进程节点进行调度。 通过使用vruntime黑红,进程调度可以更加高效、公平。当新的进程加入系统时,将根据其vruntime值插入到黑红中的合适位置。而在每次调度时,系统会选择具有最小vruntime的进程进行运行,保证了优先级最高的进程能够被及时调度。 vruntime黑红的设计不仅提高了调度效率,还使得调度更公平,避免了某个进程长期占用CPU的情况。它遵循了红黑树的平衡特性,保证了的高度相对较低,从而加速了插入和查找操作。 总之,vruntime黑红是一种用于进程调度的数据结构,通过使用虚拟运行时间作为优先级指标,并通过黑红的平衡特性实现了高效、公平的进程调度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值