洛谷題單指南-二叉樹-P5076 【深基16.例7】普通二叉樹(簡化版)

江城伍月發表於2024-03-14

原題連結:https://www.luogu.com.cn/problem/P5076

題意解讀:此題本質上是要實現一個二叉搜尋樹的功能。

解題思路:

從資料規模10^4來看,只要複雜度在n^2範圍內基本上是可以透過的,下面給出兩種做法:

1、有序陣列法

對應5個操作的實現邏輯如下:

操作一:查x的排名。直接透過二分查詢>=x的第一個數的位置pos,pos即x的排名,複雜度O(logN);

操作二:查排名x的數。直接返回x下標的元素,複雜度O(1);

操作三:x的前驅。透過二分查詢>=x的最小的數的位置pos,x的前驅即pos-1位置的數,不存在要輸出 −2147483647,複雜度O(logN);

操作四:x的後繼。透過二分查詢<=x的最大的數的位置pos,x的後繼即pos+1位置的數,不存在要輸出2147483647,複雜度O(logN);

操作五:插入x。透過二分查詢>=x的最小的數的位置pos,如果pos不存在,則將x新增到最後,否則從pos開始把所有數往後移一位,將x放入pos,複雜度<=O(logN + N)。

總體複雜度<O(N^2)

100分程式碼:

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

const int N = 10005;

int a[N], idx;

int bs1(int x)
{
    int l = 1, r = idx, ans = -1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(a[mid] >= x) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    if(ans == -1) ans = idx + 1; //如果不存在,要找的位置就是當前最後一個數的下一個位置
    return ans;
}

int bs2(int x)
{
    int l = 1, r = idx, ans = -1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(a[mid] <= x) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    if(ans == -1) ans = 0; //如果不存在,要找的位置就是當前第一個數前一個位置
    return ans;
}

int main()
{
    int q, op, x;
    cin >> q;
    while(q--)
    {
        cin >> op >> x;
        if(op == 1)
        {
            int r = bs1(x); //查詢第一個>=x的位置,即x的排名
            cout << r << endl;
        } 
        else if(op == 2) cout << a[x] << endl; //返回排名x的數
        else if(op == 3) 
        {
            int pos = bs1(x); //查詢>=x的最小的數的位置pos
            if(pos - 1 > 0) cout << a[pos - 1] << endl; //x的前驅即pos-1位置的數
            else cout << -2147483647 << endl; //不存在要輸出 −2147483647
        }
        else if(op == 4) 
        {
           int pos = bs2(x); //查詢<=x的最大的數的位置pos
           if(pos + 1 <= idx) cout << a[pos + 1] << endl; //x的後繼即pos+1位置的數
           else cout << 2147483647 << endl; //不存在要輸出2147483647
        }
        else
        {
            int pos = bs1(x); //查詢>=x的最小的數的位置pos
            
            if(pos == idx + 1) a[++idx] = x; //如果沒有找到,說明所有數都比x小,新增到最後
            else 
            {
                for(int i = idx; i >= pos; i--) 
                    a[i + 1] = a[i]; //從pos開始把所有數往後移一位
                a[pos] = x; //將x放入pos
                idx++; //最後一個元素的位置更新
            }
        }
    }

    return 0;
}

2、set法(底層是紅黑樹-一種平衡的二叉搜尋樹)

set有兩個實現了二分查詢功能的函式要介紹一下:

s.lower_bound(x); //返回容器中第一個大於等於x的數的迭代器

s.upper_bound(x);//返回容器中第一個大於x的數的迭代器

對應5個操作的實現邏輯如下:

操作一:查x的排名。透過lower_bound(x)查詢第一個>=x的數的迭代器it,從迭代器s.begin()遍歷到it,累計cnt即為x的排名,複雜度<=O(logN + N);

操作二:查排名x的數。從迭代器s.begin()遍歷x次,取第x個元素的值,複雜度<=O(N);

操作三:x的前驅。透過lower_bound(x)查詢第一個>=x的數的迭代器it,x的前驅即it--位置的數,不存在要輸出 −2147483647,複雜度O(logN);

操作四:x的後繼。透過upper_bound(x)查詢第一個>x的數的迭代器it,x的後繼*it,不存在要輸出2147483647,複雜度O(logN);

操作五:插入x。透過insert(x)插入資料,複雜度O(logN)。

總體複雜度<O(N^2)

100分程式碼:

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

set<int> tree;

int main()
{
    int q, op, x;
    cin >> q;
    while(q--)
    {
        cin >> op >> x;
        if(op == 1)
        {
            int cnt = 1;
            set<int>::iterator end = tree.lower_bound(x);  //查詢第一個>=x的數的迭代器
            for(set<int>::iterator it = tree.begin(); it != end; it++) cnt++; //從迭代器s.begin()遍歷到it,累計cnt即為x的排名
            cout << cnt << endl;
        } 
        else if(op == 2) 
        {
            int cnt = 1;
            set<int>::iterator it = tree.begin();
            while(it != tree.end() && cnt != x) it++, cnt++; //從迭代器s.begin()遍歷x次,取第x個元素的值
            cout << *it << endl;
        }
        else if(op == 3) 
        {
            set<int>::iterator it = tree.lower_bound(x);  //查詢第一個>=x的數的迭代器it
            if(it != tree.begin()) cout << *(--it) << endl; //x的前驅即--it位置的數
            else cout << -2147483647 << endl; //不存在要輸出 −2147483647
        }
        else if(op == 4) 
        {
            set<int>::iterator it = tree.upper_bound(x); //查詢第一個>x的數的迭代器it
            if(it != tree.end()) cout << *it << endl; //x的後繼*it
            else cout << 2147483647 << endl; //不存在要輸出2147483647
        }
        else tree.insert(x); //插入資料
    }

    return 0;
}

相關文章