题意
将一系列给定数字顺序插人一个初始为空的最小堆 H[],随后判断一系列相关问题是否为真,命题分为下列几种:
x is the root:x是根结点。
x and y are siblings:x和y是兄弟结点。
x is the parent of y:x是y的父结点。
x is a child of y:x是y的一个子结点。
Input
每组测试第1行包含2个正整数N(≤1000)和M(≤20),分别是插入元素的个数以及需要判断的命题数;
下一行给出区间[-10 000, 10 000]内的N个要被插人一个初始为空的小顶堆的整数;
之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。
Output
对输入的每个命题,如果为真,则在一行中输出T,否则输出F。
思路
首先建堆,然后对每个判断语句找到其在堆中的位置,判断对应的是否成立。
建堆:输入的时候进行调整,因为题目要求最小堆,所以将该节点和父节点比较,如果该节点小于父节点的话就将该节点向上调整,这样最后的数组就满足最小堆的性质啦。
性质:
x的父节点为x/2,子节点为2x,2x+1
判断语句:
首先编写函数get(x)表示得到x在堆里的下标,当然也可以提前用map预处理下。
- x is the root,判断x在堆里的下标是否为1
- x and y are siblings:判断x和y在堆里的下标的父节点是否相同
- x is the parent of y:判断y在堆的下标/2是否为x
- x is a child of y:判断x在堆里的下标/2是否为y
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
#define debug(x) cout<<#x<<":"<<x<<endl;
int n,m,a[maxn];
int get(int x){
for(int i=1;i<=n;i++)
if(a[i]==x) return i;
return -1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
int now=i;
while(now>1&&a[now]<a[now/2]){
swap(a[now],a[now/2]);
now/=2;
}
}
/// for(int i=1;i<=n;i++) cout<<a[i]<<" ";
/// puts("");
while(m--){
int x,y;string s;
cin>>x>>s;
if(s=="and"){ ///x and y are siblings:x和y是兄弟结点。
cin>>y;
cin>>s;cin>>s;
if(get(x)/2==get(y)/2) puts("T");
else puts("F");
}
else{
cin>>s;
if(s=="a"){ ///x is a child of y:x是y的一个子结点
cin>>s;cin>>s;cin>>y;
if(get(x)/2==get(y)) puts("T");
else puts("F");
}
else{
cin>>s;
if(s=="root"){
if(get(x)==1) puts("T");
else puts("F");
}
else{
cin>>s>>y;
if(get(y)/2==get(x)) puts("T");
else puts("F");
}
}
}
}
return 0;
}