洛谷题单指南-二叉树-P5076 【深基16.例7】普通二叉树(简化版)

原题链接: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;
}

 

posted @ 2024-03-14 16:36  五月江城  阅读(123)  评论(0编辑  收藏  举报