AtCoder题解 —— AtCoder Beginner Contest 188 —— C - ABC Tournament —— 数据结构之二叉树

题目相关

题目链接

AtCoder Beginner Contest 188 C 题,https://atcoder.jp/contests/abc188/tasks/abc188_c。

Problem Statement

2 N 2^N 2N players, labeled 1 1 1 through 2 N 2^N 2N, will compete against each other in a single-elimination programming tournament.
The rating of Player i i i is A i A_i Ai. Any two players have different ratings, and a match between two players always results in the victory of the player with the higher rating.
The tournament looks like a perfect binary tree. Formally, the tournament will proceed as follows:

  • For each integer i = 1 , 2 , 3 , … , N i=1,2,3,…,N i=1,2,3,,N in this order, the following happens.
    • For each integer j ( 1 ≤ j ≤ 2 N − i ) j(1≤j≤2^{N−i}) j(1j2Ni), among the players who have never lost, the player with the ( 2 j − 1 ) (2j−1) (2j1)-th smallest label and the player with the 2 j 2j 2j-th smallest label play a match against each other.

Find the label of the player who will take second place, that is, lose in the final match.

Input

Input is given from Standard Input in the following format:
N N N
A 1 A 2 ⋯ A 2 N A_1 A_2 \cdots A_{2^N} A1A2A2N

Output

Print the label of the player who will take second place.

Sample 1

Sample Input 1

2
1 4 2 5

Sample Output 1

2

Explaination

First, there will be two matches between Players 1 1 1 and 2 2 2 and between Players 3 3 3 and 4 4 4. According to the ratings, Players 2 2 2 and 4 4 4 will win.
Then, there will be a match between Players 2 2 2 and 4 4 4, and the tournament will end with Player 4 4 4 becoming champion.
The player who will lose in the final match is Player 2 2 2, so we should print 2 2 2.

Sample 2

Sample Input 2

2
3 1 5 4

Sample Output 2

1

Explaination

First, there will be two matches between Players 1 1 1 and 2 2 2 and between Players 3 3 3 and 4 4 4. According to the ratings, Players 1 1 1 and 3 3 3 will win.
Then, there will be a match between Players 1 1 1 and 3 3 3, and the tournament will end with Player 3 3 3 becoming champion.
The player who will lose in the final match is Player 1 1 1, so we should print 1 1 1.

Sample 3

Sample Input 3

4
6 13 12 5 3 7 10 11 16 9 8 15 2 1 14 4

Sample Output 3

2

Constraints

  • 1 ≤ N ≤ 16 1≤N≤16 1N16
  • 1 ≤ A i ≤ 1 0 9 1≤A_i≤10^9 1Ai109
  • A i A_i Ai are pairwise different.
  • All values in input are integers.

题解报告

题目翻译

2 N 2^N 2N 个玩家,编号从 1 1 1 2 N 2^N 2N。这些玩家正在进行一对一编程淘汰赛。第 i i i 个玩家的胜率用 A i A_i Ai 表示,任意两个不同的玩家的胜率是不一样的。两个玩家进行淘汰的时候,淘汰胜率较小的哪个玩家。问最终获得第二名的玩家编号是多少。

样例数据分析

我们使用样例数据 3 3 3 来分析一下,整个淘汰的过程。

第一次

AtCoder题解 —— AtCoder Beginner Contest 188 —— C - ABC Tournament —— 数据结构之二叉树_第1张图片

第二次

AtCoder题解 —— AtCoder Beginner Contest 188 —— C - ABC Tournament —— 数据结构之二叉树_第2张图片

第三次

AtCoder题解 —— AtCoder Beginner Contest 188 —— C - ABC Tournament —— 数据结构之二叉树_第3张图片
这样,我们可以知道第二名的编号为 2 2 2

题目分析

从上面的数据分析可以看到。本题的考点就是一个二叉搜索树,因此最简单的方法就是使用递归来实现。这里我用数组来实现,这样能更好的理解整个数据变化过程。
有几个二叉树的基本性质需要了解。
1、当前节点编号为 i i i,其父节点编号为 i 2 \frac{i}{2} 2i
2、当前节点编号为 i i i,其右兄弟节点编号为 i + 1 i+1 i+1
这样,我们通过控制数组下标,来实现样例数据分析的过程。

如何记录索引

我们使用结构体。结构体定义如下。

typedef struct _DATA {
    int value;
    int idx;
} DATA;

数据范围分析

注意,本题定义的数组大小为 2 N 2^N 2N。因此 N N N 的最大值为 16 16 16,数组最大为 65536 65536 65536
数据的最大值为 1 0 9 10^9 109,因此用 int 可以。

AC 代码

//https://atcoder.jp/contests/abc188/tasks/abc188_a
//A - Three-Point Shot
#include 

using namespace std;

//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL

const int MAXN = 65538;
typedef struct _DATA {
    int value;
    int idx;
} DATA;
DATA a[MAXN];

int main() {
#ifndef __LOCAL
    //这部分代码需要提交到OJ,本地调试不使用
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif
    int n;
    cin>>n;
    n=pow(2, n);
    for (int i=1; i<=n; i++) {
        cin>>a[i].value;
        a[i].idx = i;
    }

    while (n>2) {
        for (int i=1; i<=n; i+=2) {
            if (a[i].value<a[i+1].value) {
                a[i/2+1].value = a[i+1].value;
                a[i/2+1].idx   = a[i+1].idx;
            } else {
                a[i/2+1].value = a[i].value;
                a[i/2+1].idx   = a[i].idx;
            }
        }
        n/=2;
    }

    if (a[1].value>a[2].value) {
        cout<<a[2].idx<<"\n";
    } else {
        cout<<a[1].idx<<"\n";
    }

#ifdef __LOCAL
    //这部分代码不需要提交到OJ,本地调试使用
    system("pause");
#endif
    return 0;
}

在这里插入图片描述

时间复杂度

O ( l o g 2 N ) O(log{2^N}) O(log2N)

空间复杂度

O(N)。

递归实现

使用完全二叉树的基本定义,我们可以实现递归。

//https://atcoder.jp/contests/abc188/tasks/abc188_a
//A - Three-Point Shot
#include 

using namespace std;

//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL

const int MAXN = 65538;
int a[MAXN];
int n;

int solve(int l, int r) {
    //出口
    if (l+1==r) {
        return a[l]>a[r]?l:r;
    }
    //递归
    int mid = (l+r)/2;
    int x=solve(l, mid);
    int y=solve(mid+1, r);
    if (l==1 && r==n) {
        cout<<(a[x]>a[y]?y:x)<<"\n";
        return 0;
    } else {
        return a[x]>a[y]?x:y;
    }
}

int main() {
#ifndef __LOCAL
    //这部分代码需要提交到OJ,本地调试不使用
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif
    cin>>n;
    //n=1<
    n=pow(2, n);
    for (int i=1; i<=n; i++) {
        cin>>a[i];
    }

    if (2==n) {
        cout<<(a[1]>a[2]?'2':'1')<<'\n';
        return 0;
    }
    solve(1, n);

#ifdef __LOCAL
    //这部分代码不需要提交到OJ,本地调试使用
    system("pause");
#endif
    return 0;
}

在这里插入图片描述没有我想象中好。递归只是代码简洁。

时间复杂度

O ( l o g 2 N ) O(log{2^N}) O(log2N)

空间复杂度

O(N)。

你可能感兴趣的:(OJ题解,#,AtCoder题解,AtCoder题解,ABC188,C题,ABC,Tournament,二叉树)