题目1541:二叉树

题目1541:二叉树

时间限制:1 秒

内存限制:128 兆

特殊判题:

提交:275

解决:47

题目描述:

旋转是二叉树的基本操作,我们可以对任意一个存在父亲节点的子节点进行旋转,包括如下几种形式(设被旋转节点为x,其父亲节点为p):
1.左旋
旋转前,x是p的右儿子。
x的左儿子(若存在)变为p的右儿子,p变为x的左儿子。如下图

2.右旋
旋转前,x是p的左儿子。
x的右儿子(若存在)变为p的左儿子,p变为x的右儿子。如下图

综上,我们可以通过检查选择前x是p的左儿子还是右儿子来判断该次旋转是左旋还是右旋。

给定一颗n个节点的二叉树,其节点由1至n编号,并给定一系列操作,如下:
1.rotate x,对编号x的节点进行旋转,若x为根节点,则不进行任何操作。
2.parent x,输出编号x的父亲节点编号,若x为根节点输出-1。
3.size x,输出以x为根节点的子树的节点个数。

输入:

输入包含多组测试用例。
每组测试用例开头为一个整数n(1<=n<=1000),代表二叉树的节点个数。
接下去n行描述,二叉树原始的状态,第i行为两个整数x,y,代表i号节点的左儿子节点为x号节点,右儿子节点为y号节点,若x或y为-1,则表示相应儿子节点不存在。编号的范围为1到n。
接下去一行为一个整数t(1<=t<=50000),代表操作的个数。
最后t行,每行代表一个对二叉树的操作,描述如上所示。

输出:

对于每组测试用例,输出操作parent x和size x查询的数据。

样例输入:
5
2 3
-1 -1
4 5
-1 -1
-1 -1
5
size 1
rotate 5
size 5
parent 3
parent 4
样例输出:
5
3
5
3


思路:计算好size存储起来,根据左旋和右旋重新改变两个size



#include <stdio.h>
#include <string.h>
struct Node
{
	int parent;
	int leftChild,rightChild;
};
Node list[1010];
int n,opNum,t;
char op[10];
int size[1010];

int fun(int curNode)
{
	if(curNode == -1)
	{
		return 0;
	}
	return size[curNode] = fun(list[curNode].leftChild) + fun(list[curNode].rightChild) + 1;
}

int Compute(int node)
{
	return (node == -1) ? 0 : size[node];
}

int main()
{
	while(scanf("%d", &n) != EOF)
	{
		memset(size, 0, sizeof(size));
		for(int i = 0; i < 1010; i++)
		{
			list[i].leftChild = -1;
			list[i].rightChild = -1;
			list[i].parent = -1;
		}
		int tempr,templ;
		for(int i = 1; i <= n; i++)
		{
			scanf("%d %d", &templ, &tempr);
			list[i].leftChild = templ;
			list[i].rightChild = tempr;
			if(templ != -1)
			{
				list[templ].parent = i;
			}
			if(tempr != -1)
			{
				list[tempr].parent = i;
			}
		}
		fun(1);
		scanf("%d", &t);
		for(int i = 0; i < t; i++)
		{
			scanf("%s %d", &op, &opNum);
			if(strcmp(op, "size") == 0)
			{
				printf("%d\n", size[opNum]);
			}
			else if(strcmp(op, "rotate") == 0)
			{
				int temp = list[opNum].parent;
				if(temp != -1)
				{
					list[opNum].parent = list[temp].parent;
					if(list[temp].parent != -1)
					{
						if(list[list[temp].parent].leftChild == temp)
						{
							list[list[temp].parent].leftChild = opNum;
						}
						else
						{
							list[list[temp].parent].rightChild = opNum;
						}
					}
					if(list[temp].leftChild == opNum)
					{
						list[temp].leftChild = list[opNum].rightChild;
						if(list[temp].leftChild != -1)
						{
							list[list[temp].leftChild].parent = temp;
						}
						list[opNum].rightChild = temp;
					}
					else
					{
						list[temp].rightChild = list[opNum].leftChild;
						if(list[opNum].leftChild != -1)
						{
							list[list[opNum].leftChild].parent = temp;
						}
						list[opNum].leftChild = temp;
					}
					list[temp].parent = opNum;
					size[opNum] = size[temp];
					size[temp] = Compute(list[temp].leftChild) + Compute(list[temp].rightChild) + 1;
				}
			}
			else if(strcmp(op,"parent") == 0)
			{
				printf("%d\n", list[opNum].parent);
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值