团体天梯练习 L2-012 关于堆的判断

发布时间 2023-04-17 15:28:57作者: Amαdeus

L2-012 关于堆的判断

将一系列给定数字顺序插入一个初始为空的小顶堆 \(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


解题思路

按照题意不断进行堆的向上调整操作,得到小顶堆,并记录每个值所在下标,看作是一颗完全二叉树。注意要使用在线调整的 \(up\) 向上调整法,如果使用离线调整的 \(down\) 向下调整法,得到的小顶堆不一定相同。

/*   一切都是命运石之门的选择  El Psy Kongroo  */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
typedef pair<double, double> pdd;
typedef pair<string, int> psi;
typedef __int128 int128;
#define PI acos(-1.0)
#define x first
#define y second
//int dx[4] = {1, -1, 0, 0};
//int dy[4] = {0, 0, 1, -1};
const int inf = 0x3f3f3f3f, mod = 1e9 + 7;

map<int, int> idx;
static const int N = 1010;
int a[N], n, m;

//向上调整法
void up(int u){
    while(u >> 1 && a[u] < a[u >> 1]){
        swap(a[u], a[u >> 1]);
        u >>= 1;
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n >> m;
    for(int i = 1; i <= n; i ++ ){
        cin >> a[i];
        up(i);       //在线调整
    }

    for(int i = 1; i <= n; i ++ ) idx[a[i]] = i;

    while(m -- ){
        bool flag;
        int x, y; cin >> x;
        string s; cin >> s;  //cin不吸收空格
        if(s == "and"){
            cin >> y; cin >> s >> s;
            flag = (idx[x] / 2 == idx[y] / 2);   //两者的父节点下标是否相同
        }else{
            cin >> s >> s;
            if(s == "root") flag = (idx[x] == 1);  //下标为1即为根节点
            else if(s == "parent"){
                cin >> s; cin >> y;
                flag = (idx[x] == idx[y] / 2);   //x是y的父节点 判断x的下标是否为y下标的1/2向下取整
            }else{
                cin >> s; cin >> y;
                flag = (idx[x] / 2 == idx[y]);   //x是y的子节点 判断y的下标是否为x下标的1/2向下取整
            }
        }

        if(flag) cout << "T" << endl;
        else cout << "F" << endl;
    }

    return 0;
}