将一系列给定数字顺序插入一个初始为空的小顶堆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的一个子结点。
输入格式:
每组测试第1行包含2个正整数N(≤ 1000)和M(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。
输出格式:
对输入的每个命题,如果其为真,则在一行中输出T,否则输出F。
5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10
F
T
F
T
- 题干要求边读入边插入堆中,如果使用 O(n)O(n)O(n) 的建堆的方式,测试点1和3会爆,
我觉得这两种建堆方式只会让同一层节点的顺序不同,比如左右儿子互换,暂时不清楚爆的原因 - 这题输入很蛋疼,如果没有读完的话,需要用getline把这一行读完,不然会对下边的数据造成影响。
- 判断兄弟节点的时候,是看两个兄弟的编号/2 是否是父亲节点的编号。
- 题目没说堆中所有的数据值不同,所以这个算法应该是个伪算法。
#include<iostream>
#include<map>
using namespace std;
const int N=1e5+10;
int h[N],n,m,sz;
// 题目中没说所有的值都是唯一的
void down(int u){
int t = u;
if(u*2<=sz&&h[u*2]<h[t])t = u*2;
if((u*2+1)<=sz&&h[u*2+1]<h[t])t = u*2+1;
if(t!=u){
swap(h[u],h[t]);
down(t);
}
}
void up(int u){
while(u>1&&(h[u]<h[u/2])){
swap(h[u],h[u/2]);
u/=2;
}
}
map<int,int>pos;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;cin>>x;
h[++sz]=x;
up(sz);
}
for(int i=1;i<=n;i++){
pos[h[i]]=i;
}
while(m--){
int x;
string s;cin>>x>>s;
int posx=pos[x];
if(s=="is"){
cin>>s;
int y;
if(s=="a"){
cin>>s>>s;
cin>>y;
int posy=pos[y];
if(posx/2==posy){// x是y的子节点
cout<<"T"<<endl;
}
else{
cout<<"F"<<endl;
}
}
else{
cin>>s;
if(s=="root"){
if(pos[x]==1){
cout<<"T"<<endl;
}
else{
cout<<"F"<<endl;
}
}
else if(s=="parent"){
cin>>s;
cin>>y;
int posy=pos[y];
if(pos[y]/2==pos[x]){
cout<<"T"<<endl;
}
else{
cout<<"F"<<endl;
}
}
}
}
else{//and 兄弟节点
int y;cin>>y;
getline(cin,s);
int posy=pos[y];
if(posx/2 == posy/2){
cout<<"T"<<endl;
}
else{
cout<<"F"<<endl;
}
}
}
}
该程序实现了一个小顶堆的构建,并对输入的节点关系进行判断。通过读入一系列数字插入空堆,然后根据给定命题判断节点间的父子、兄弟、根节点等关系。输入数据可能包含重复值,输出为每个命题的真假结果。
466

被折叠的 条评论
为什么被折叠?



