吐血整理 PTA 团体程序设计天梯赛题解

去年参加了一次天梯赛,毕竟才大一,水平有限,L1 基本答了,L2 混了几题部分正确,L3 题目还没点开过。今年再战,顺便更新更新题解,也做本身复习用。另外,日常 HDU 的题目作多了,养成了动不动就用 scanfprintf 的习惯,其实 PTA 的题基本上用 cincout 都能过的,因此 下面的代码中的全部 c 语言部分为了方便,均可以换成 c++,毕竟 scanfprintf 不只字母多,里面还要打一堆 % 太繁琐了。

题解在不按期更新中,水平有限,最多也就作到 L2,欢迎在评论中提出问题,一块儿讨论。node

2020-01-09 更新: L1-015 ~ L1-017
2020-01-15 更新: L1-018 ~ L1-020
2020-01-20 更新: L2-002, L2-003

刷题连接 👉ios

关于 bits/stdc++.h

一个“万能头文件”,基本上经常使用的 STL 都在里面了,ACM 比赛就是怎么高效怎么来,这么好用的东西不用白不用。c++

L1 部分题解

因为 L1 题目广泛简单,因此备注比较少,后面的 L2 题目会适当加上备注。算法

L1-001 Hello World (5 分)

pta 最难的一题!!!数组

#include <bits/stdc++.h>
using namespace std;
int main() {
    cout << "Hello World!";
    return 0;
}

L1-002 打印沙漏 (20 分)

由于图形上下对称,因此能够先计算出上半图形的高度、宽度,这题主要就是考察逻辑思惟。数据结构

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, height = 1, width = 1;
    char ch;
    cin >> n >> ch;
    --n;  // 先扣去最中间的一个字符
    while (true) {
        if (n - 2 * (width + 2) >= 0) {
            ++height;
            width += 2;
            n -= 2 * width;
        } else
            break;
    }
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < i; ++j) cout << ' ';
        for (int j = 0; j < 2 * height - 1 - 2 * i; ++j) cout << ch;
        cout << '\n';
    }
    for (int i = 0; i < height - 1; ++i) {
        for (int j = 0; j < height - 2 - i; ++j) cout << ' ';
        for (int j = 0; j < 2 * (i + 1) + 1; ++j) cout << ch;
        cout << '\n';
    }
    cout << n;
    return 0;
}

L1-003 个位数统计 (15 分)

虽然题目描述须要输入正整数,可是输入正整数须要一次一次取模才能获得各位,直接以字符串的方式输入就很简单。post

#include <bits/stdc++.h>

using namespace std;

int main() {
    int cnt[10] = {0};
    string num;
    cin >> num;
    for (int i = 0; i < num.size(); ++i) ++cnt[num[i] - '0'];
    for (int i = 0; i < 10; ++i)
        if (cnt[i] > 0) cout << i << ':' << cnt[i] << '\n';
    return 0;
}

L1-004 计算摄氏温度 (5 分)

没有什么难点,L1 不少题都像这样。测试

#include <bits/stdc++.h>

using namespace std;

int main() {
    int F;
    cin >> F;
    int C = 5 * (F - 32) / 9;
    cout << "Celsius = " << C;
    return 0;
}

L1-005 考试座位号 (15 分)

把试机座位号看成下标,而后准考证号和考试座位号分别存入 a, b 数组,最后输出就好。(准考证号 16 位,int 装不下)优化

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
LL x, a[1005];
int n, m, y, z, b[1005];

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%lld%d%d", &x, &y, &z);
        a[y] = x;
        b[y] = z;
    }
    scanf("%d", &m);
    for (int i = 0; i < m; ++i) {
        scanf("%d", &y);
        printf("%lld %d\n", a[y], b[y]);
    }
    return 0;
}

L1-006 连续因子 (20 分)

用循环模拟出可能的连续因子序列。须要注意几个优化的地方,for (int i = 2; i <= sqrt(n); ++i),很好理解,大于 sqrt(n) 的数再随便乘一下就大于 n 了,确定就不是因子,因此这里只走到 sqrt(n)ui

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
LL n, tmp;
int start, len;

int main() {
    scanf("%lld", &n);
    for (int i = 2; i <= sqrt(n); ++i) {
        tmp = 1;
        for (int j = i; tmp * j <= n; ++j) {
            tmp *= j;
            if (n % tmp) break;  // 若是tmp不是n的因子,再乘任何数也不是
            if (j - i + 1 > len) {
                start = i;
                len = j - i + 1;
            }
        }
    }
    if (!start) {
        start = n;
        len = 1;
    }
    printf("%d\n%d", len, start);
    for (int i = 1; i < len; ++i) printf("*%d", start + i);
    return 0;
}

L1-007 念数字 (10 分)

只要注意行尾不能有空格就行了。

#include <bits/stdc++.h>

using namespace std;

string a[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};

int main() {
    string s;
    cin >> s;
    if (s[0] == '-')
        cout << "fu";
    else
        cout << a[s[0] - '0'];
    for (int i = 1; i < s.size(); ++i)
        cout << ' ' << a[s[i] - '0'];
    return 0;
}

L1-008 求整数段和 (10 分)

只能说 pta 的题太细节了,不难的一题可是正确率很低,由于很容易出现恰好 5 个数时,最后连换两行的状况。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a, b, sum = 0;
    scanf("%d%d", &a, &b);
    for (int i = a; i <= b; ++i) {
        sum += i;
        printf("%5d", i);
        if ((i - a + 1) % 5 == 0)
            printf("\n");
        else if (i == b)
            printf("\n");
    }
    printf("Sum = %d", sum);
    return 0;
}

L1-009 N 个数求和 (20 分)

分数求和,难点就是通分,须要求最大公约数,能够用欧几里得算法(gcd)求得。最后还有一点须要注意,测试数据是在长整型范围内的。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;

LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); }

int main() {
    char c;
    int n;
    LL x, y, tmp;
    cin >> n;
    cin >> x >> c >> y;
    LL sx = x, sy = y;
    for (int i = 1; i < n; ++i) {
        cin >> x >> c >> y;
        tmp = sy / gcd(sy, y) * y;
        sx = sx * (tmp / sy) + x * (tmp / y);
        sy = tmp;
    }
    LL num = sx / sy;
    sx %= sy;
    tmp = gcd(sx, sy);
    sx /= tmp;
    sy /= tmp;
    if (sx == 0)
        cout << num;
    else if (num == 0)
        cout << sx << '/' << sy;
    else
        cout << abs(num) << ' ' << sx << '/' << sy;
    return 0;
}

L1-010 比较大小 (10 分)

简单的排个序。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a[3];
    for (int i = 0; i < 3; ++i)
        cin >> a[i];
    sort(a, a + 3);
    cout << a[0] << "->" << a[1] << "->" << a[2];
    return 0;
}

L1-011 A-B (20 分)

字符串,查找,删除。

#include <bits/stdc++.h>

using namespace std;

int main() {
    string a, b;
    getline(cin, a);
    getline(cin, b);
    for (int i = 0; i < b.size();) {
        if (a.find(b[i]) != -1)
            a.erase(a.find(b[i]), 1);
        else
            ++i;
    }
    cout << a;
    return 0;
}

L1-012 计算指数 (5 分)

水题。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    cout << "2^" << n << " = " << pow(2, n);
    return 0;
}

L1-013 计算阶乘和 (10 分)

水题。

#include <bits/stdc++.h>
using namespace std;

int fac(int x) { return x == 1 ? 1 : fac(x - 1) * x; }

int main() {
    int n, sum = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        sum += fac(i);
    cout << sum;
    return 0;
}

L1-014 简单题 (5 分)

水题三连。

#include <iostream>
using namespace std;
int main() {
    cout << "This is a simple problem.";
    return 0;
}

L1-015 跟奥巴马一块儿画方块 (15 分)

主要就是四舍五入的部分,用二进制骚一下。

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    char c;
    cin >> n >> c;
    int m = (n & 1) ? n / 2 + 1 : n / 2;  // 四舍五入
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j)
            cout << c;
        cout << endl;
    }
    return 0;
}

L1-016 查验身份证 (15 分)

水题,就是麻烦了点。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    int b[] = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    int n;
    cin >> n;
    string s;
    bool flag = false;
    while (n--) {
        int sum = 0;
        cin >> s;
        for (int i = 0; i < s.size() - 1; ++i)
            sum += (s[i] - '0') * a[i];
        sum %= 11;
        if (b[sum] != s.back()) {
            cout << s << endl;
            flag = true;
        }
    }
    if (!flag)
        cout << "All passed";
    return 0;
}

L1-017 到底有多二 (15 分)

cout << setiosflags(ios::fixed) << setprecision(2) 控制小数点位数。

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    int cnt = 0;
    double flag = 1;
    if (s[0] == '-') {
        flag *= 1.5;
        s.erase(s.begin(), s.begin() + 1);
    }
    if ((s.back() - '0') % 2 == 0) flag *= 2;
    for (int i = 0; i < s.size(); ++i)
        if (s[i] == '2') ++cnt;
    cout << setiosflags(ios::fixed) << setprecision(2)
         << cnt * flag / s.size() * 100 << '%';
    return 0;
}

L1-018 大笨钟 (10 分)

注意 12 点整不须要敲,过了 12 点就要敲。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int h, m;
    scanf("%d:%d", &h, &m);
    if (h >= 0 && h < 12 || h == 12 && m == 0)
        printf("Only %02d:%02d.  Too early to Dang.", h, m);
    else {
        if (m == 0)
            h -= 12;
        else
            h -= 11;
        while (h--)
            printf("Dang");
    }
    return 0;
}

L1-019 谁先倒 (15 分)

这题比较坑,假如酒量给的是 1,须要喝 2 杯才能倒,因此输入两人的酒量后,都须要加 1。另外题目描述第二行输入一个正整数 N,实际上 N 根本没用。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, m, _, a, b, c, d;
    int cnt1 = 0, cnt2 = 0;
    cin >> n >> m >> _;
    ++n, ++m;
    while (n && m) {
        cin >> a >> b >> c >> d;
        int tmp = a + c;
        if (b == tmp && d != tmp) {
            --n;
            ++cnt1;
        } else if (b != tmp && d == tmp) {
            --m;
            ++cnt2;
        }
    }
    if (n)
        cout << "B\n" << cnt1;
    else
        cout << "A\n" << cnt2;
    return 0;
}

L1-020 帅到没朋友 (20 分)

朋友圈人数若是为 1,不作处理。大于 1 的话,说明有朋友,作个标记,注意输出格式。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, k, id;
    vector<bool> fri(100000, false), vis(100000, false);
    cin >> n;
    while (n--) {
        cin >> k;
        if (k == 1)
            cin >> id;
        else {
            while (k--) {
                cin >> id;
                fri[id] = true;
            }
        }
    }
    cin >> n;
    bool flag = false;
    while (n--) {
        cin >> id;
        if (!fri[id] && !vis[id]) {
            if (flag) cout << ' ';
            cout << setfill('0') << setw(5) << id;
            vis[id] = flag = true;
        }
    }
    if (!flag) cout << "No one is handsome";
    return 0;
}

L1-059 敲笨钟 (20 分)

就是几个知识点,getline 前用 cin.get() 吸取回车,而后一些字符串基本操做,find 正向查找,rfind 反向查找,substr 切割。最后就是须要考虑到一种特殊状况,逗号前的字符不足 3 个,那么直接去使用 str.substr(p - 3, 3) == "ong" 判断的话就会出现错误(最后一组测试数据),因此须要加上 p >= 3 这个前提条件。

#include <bits/stdc++.h>

using namespace std;

int main() {
    string str;
    int n;
    cin >> n;
    cin.get();
    while (n--) {
        getline(cin, str);
        int p = str.find(',');
        if (p >= 3 && str.substr(p - 3, 3) == "ong" &&
            str.substr(str.size() - 4, 3) == "ong") {
            p = str.size();
            for (int i = 0; i < 3; ++i) p = str.rfind(' ', p - 1);
            cout << str.substr(0, p) << " qiao ben zhong.\n";
        } else
            cout << "Skipped\n";
    }
    return 0;
}

L2 部分题解

[最短路] L2-001 紧急救援 (25 分)

复杂了一些的最短路,用优先队列对查找最小dis的过程作了优化。dis[i]表示起点到i的最短路长度,pre[i]表示i的前驱,cnt[i]表示到达i的最短路条数,sum[i]表示最多的救援队数目。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 505

using namespace std;

int n, m, s, d, x, y, z;
int num[N], path[N][N], dis[N], pre[N], cnt[N], sum[N];
bool vis[N];

struct Node {
    int key, value;
    Node(int k, int v) {
        key = k;
        value = v;
    }
    bool operator<(const Node &a) const { return value > a.value; }
};

void dijkstra() {
    pre[s] = -1;
    cnt[s] = 1;
    sum[s] = num[s];
    dis[s] = 0;
    priority_queue<Node> q;
    q.push(Node(s, 0));
    while (!q.empty()) {
        int k = q.top().key;
        q.pop();
        if (vis[k]) continue;
        vis[k] = true;
        for (int i = 0; i < n; ++i) {
            if (!vis[i]) {
                int cur_dis = dis[k] + path[k][i];
                int cur_sum = sum[k] + num[i];
                if (cur_dis < dis[i]) {
                    dis[i] = cur_dis;
                    pre[i] = k;
                    cnt[i] = cnt[k];
                    sum[i] = cur_sum;
                } else if (cur_dis == dis[i]) {
                    cnt[i] += cnt[k];
                    if (cur_sum > sum[i]) {
                        sum[i] = cur_sum;
                        pre[i] = k;
                    }
                }
                q.push(Node(i, dis[i]));
            }
        }
    }
    printf("%d %d\n", cnt[d], sum[d]);
    stack<int> stk;
    int k = d;
    while (k != -1) {
        stk.push(k);
        k = pre[k];
    }
    printf("%d", stk.top());
    stk.pop();
    while (!stk.empty()) {
        printf(" %d", stk.top());
        stk.pop();
    }
    printf("\n");
}

int main() {
    memset(path, INF, sizeof(path));
    memset(dis, INF, sizeof(dis));
    scanf("%d%d%d%d", &n, &m, &s, &d);
    for (int i = 0; i < n; ++i) scanf("%d", &num[i]);
    for (int i = 0; i < m; ++i) {
        scanf("%d%d%d", &x, &y, &z);
        path[x][y] = path[y][x] = z;
    }
    dijkstra();
    return 0;
}

[空间换时间] L2-002 链表去重 (25 分)

典型的空间换时间,若是按照是否重复而后一个一个删除重复的,确定会超时。vis 数组作标记,没重复就放到第一个队列里,重复的放到第二个队列里,最后读一遍两个队列就好,复杂度差很少是 O(n)

#include <bits/stdc++.h>
using namespace std;

struct Node {
    int data, next;
};

int head, n, a, b, c;
vector<Node> node(100005);
vector<bool> vis(10005);
queue<int> q1, q2;

int main() {
    scanf("%d%d", &head, &n);
    while (n--) {
        scanf("%d%d%d", &a, &b, &c);
        node[a].data = b;
        node[a].next = c;
    }
    for (int i = head; i != -1; i = node[i].next) {
        if (!vis[abs(node[i].data)]) {
            vis[abs(node[i].data)] = true;
            q1.push(i);
        } else
            q2.push(i);
    }
    int pos = q1.front();
    q1.pop();
    printf("%05d %d ", pos, node[pos].data);
    while (!q1.empty()) {
        pos = q1.front();
        q1.pop();
        printf("%05d\n%05d %d ", pos, pos, node[pos].data);
    }
    printf("-1\n");
    if (!q2.empty()) {
        pos = q2.front();
        q2.pop();
        printf("%05d %d ", pos, node[pos].data);
        while (!q2.empty()) {
            pos = q2.front();
            q2.pop();
            printf("%05d\n%05d %d ", pos, pos, node[pos].data);
        }
        printf("-1");
    }
    return 0;
}

[贪心] L2-003 月饼 (25 分)

基本的结构体排序加贪心,可是这个 C++ 里的小数真是奇怪啊,不知道精度发生了什么神奇的错误,下面第一个代码提交一直有一组数据过不了,把 int 换成 double 就对了???。。。??

#include <bits/stdc++.h>
using namespace std;

struct Node {
    int x, y;
    double z;
    bool operator<(const Node &node) const { return z > node.z; }
} a[1005];

int n, d;

int main() {
    cin >> n >> d;
    for (int i = 0; i < n; ++i) cin >> a[i].x;
    for (int i = 0; i < n; ++i) {
        cin >> a[i].y;
        a[i].z = a[i].y * 1.0 / a[i].x;
    }
    sort(a, a + n);
    double sum = 0;
    for (int i = 0; i < n; ++i) {
        if (d >= a[i].x) {
            d -= a[i].x;
            sum += a[i].y;
        } else {
            sum += d * a[i].z;
            break;
        }
    }
    cout << fixed << setprecision(2) << sum;
    return 0;
}

正确代码,太坑了吧:

#include <bits/stdc++.h>
using namespace std;

struct Node {
    double x, y, z;  // x, y 换成 double
    bool operator<(const Node &node) const { return z > node.z; }
} a[1005];

int n;
double d;  // d 换成 double

int main() {
    cin >> n >> d;
    for (int i = 0; i < n; ++i) cin >> a[i].x;
    for (int i = 0; i < n; ++i) {
        cin >> a[i].y;
        a[i].z = a[i].y / a[i].x;
    }
    sort(a, a + n);
    double sum = 0;
    for (int i = 0; i < n; ++i) {
        if (d >= a[i].x) {
            d -= a[i].x;
            sum += a[i].y;
        } else {
            sum += d * a[i].z;
            break;
        }
    }
    cout << fixed << setprecision(2) << sum;
    return 0;
}

[搜索二叉树前序转后序] L2-004 这是二叉搜索树吗? (25 分)

本觉得上完数据结构的课应该就会各类树了,结果发现本身仍是太年轻。这题按照二叉搜索树的性质建树,先试试是否是二叉搜索树,再试试是否是二叉搜索树的“镜像”,若是最后能建成就顺便输出后序遍历。

#include <bits/stdc++.h>

using namespace std;

int n, pre[1005], post[1005], cnt = 0;
bool flag;

void build(int l, int r) {
    if (l > r) return;
    int i = l + 1, j = r;
    if (!flag) {
        while (i <= r && pre[i] < pre[l]) ++i;
        while (l < j && pre[j] >= pre[l]) --j;
    } else {
        while (i <= r && pre[i] >= pre[l]) ++i;
        while (l < j && pre[j] < pre[l]) --j;
    }
    if (i - j != 1) return;
    build(l + 1, j);
    build(i, r);
    post[cnt++] = pre[l];
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%d", &pre[i]);
    build(0, n - 1);
    if (cnt != n) {
        flag = true;
        cnt = 0;
        build(0, n - 1);
    }
    if (cnt != n)
        printf("NO\n");
    else {
        printf("YES\n");
        printf("%d", post[0]);
        for (int i = 1; i < cnt; ++i) printf(" %d", post[i]);
        printf("\n");
    }
    return 0;
}

[最长回文子串] L2-008 最长对称子串 (25 分)

马拉车算法模板题,c(center)表示中间点,r(right)表示回文串的右边界。具体算法思路不说了,还有须要理解的就是 r 关于 c 的对称点为2 * c - i

#include <bits/stdc++.h>

using namespace std;

int manacher(string s) {
    string str = "$#";
    for (int i = 0; i < s.size(); ++i) {
        str.push_back(s[i]);
        str.push_back('#');
    }
    int c = 0, r = 0;
    vector<int> p(str.size());
    for (int i = 1; i < p.size(); ++i) {
        p[i] = r > i ? min(p[2 * c - i], r - i + 1) : 1;
        while (str[i - p[i]] == str[i + p[i]]) ++p[i];
        if (r - c + 1 < p[i]) {
            c = i;
            r = i + p[i] - 1;
        }
    }
    // return s.substr((2 * c - r) / 2, r - c);
    return r - c;
}

int main() {
    string s;
    getline(cin, s);
    cout << manacher(s);
    return 0;
}

[结构体排序] L2-009 抢红包 (25 分)

结构体排序,输入的钱是分为单位,最后输出时除以 100.0 获得元。用结构体储存每一个人的编号,收入,抢到红包数。

#include <bits/stdc++.h>
#define N 10005

using namespace std;

struct Node {
    int key, sum, cnt;
    Node() : sum(0), cnt(0) {}
} a[N];

int n, k, x, y;

bool cmp(Node a, Node b) {
    if (a.sum == b.sum) {
        if (a.cnt == b.cnt)
            return a.key < b.key;
        return a.cnt > b.cnt;
    }
    return a.sum > b.sum;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        a[i].key = i;
        scanf("%d", &k);
        while (k--) {
            scanf("%d%d", &x, &y);
            a[i].sum -= y;
            a[x].sum += y;
            ++a[x].cnt;
        }
    }
    sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; ++i)
        printf("%d %.2f\n", a[i].key, a[i].sum / 100.0);
    return 0;
}

[并查集] L2-010 排座位 (25 分)

并查集,若是两我的是朋友关系就合并,不然,用flag数组标记两人是敌人。最后直接判断一下输出就好。

#include <bits/stdc++.h>
#define N 105

using namespace std;

int n, m, k, x, y, z;
int f[N], _rank[N] = {0}, flag[N][N] = {false};

int _find(int x) {
    return x == f[x] ? x : f[x] = _find(f[x]);  // 路径压缩
}

void _union(int x, int y) {
    int f1 = _find(x), f2 = _find(y);
    if (f1 != f2) {
        if (_rank[f1] < _rank[f2])  // 按秩合并
            f[f1] = f2;
        else {
            f[f2] = f1;
            if (_rank[f1] == _rank[f2])
                ++_rank[f1];
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; ++i)
        f[i] = i;
    while (m--) {
        scanf("%d%d%d", &x, &y, &z);
        if (z == 1)
            _union(x, y);
        else
            flag[x][y] = flag[y][x] = true;
    }
    while (k--) {
        scanf("%d%d", &x, &y);
        if (_find(x) == _find(y)) {
            if (!flag[x][y])
                printf("No problem\n");
            else
                printf("OK but...\n");
        } else {
            if (!flag[x][y])
                printf("OK\n");
            else
                printf("No way\n");
        }
    }
    return 0;
}

[最小堆] L2-012 关于堆的判断 (25 分)

肝了我一晚,怎么提交都是部分正确,我是真的无奈,直到看到有个题解:“用线性调整 heap 的话是不对的,题目要求是一个一个插入空的 MinHeap,因此只能插入,上浮,插入,上浮,插入,上浮。。。”,然而我试了一晚线性建堆。

思路很粗暴,先建堆(思路就是上面那句话,采用上浮的方式,加一个数浮一次),而后用 stringstream 把单词分割出来装进 vector,剩下就是简单判断。

#include <bits/stdc++.h>
#define N 1005

using namespace std;

int n, m, a[N];
string s;
stringstream ss;
vector<string> v;

void swim(int i) {
    int parent = (i - 1) / 2;
    if (parent >= 0 && a[parent] > a[i]) {
        swap(a[i], a[parent]);
        swim(parent);
    }
}

int toInt(string &s) {
    stringstream ss;
    ss << s;
    int x;
    ss >> x;
    return x;
}

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
        swim(i);
    }
    cin.get();  // 吸取回车
    for (int i = 0; i < m; ++i) {
        getline(cin, s);
        ss << s;
        while (ss >> s) v.push_back(s);
        if (v[3] == "root") {
            if (toInt(v[0]) == a[0])
                cout << "T\n";
            else
                cout << "F\n";
        } else if (v[4] == "siblings") {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v[2])) - a;
            if (((p1 - 1) >> 1) == ((p2 - 1) >> 1))
                cout << "T\n";
            else
                cout << "F\n";
        } else if (v[3] == "parent") {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v.back())) - a;
            if ((p2 - 1) >> 1 == p1)
                cout << "T\n";
            else
                cout << "F\n";
        } else {
            int p1 = find(a, a + n, toInt(v[0])) - a;
            int p2 = find(a, a + n, toInt(v.back())) - a;
            if ((p1 - 1) >> 1 == p2)
                cout << "T\n";
            else
                cout << "F\n";
        }
        v.clear();
        ss.clear();
    }
    return 0;
}
相关文章
相关标签/搜索