PTA团体程序设计天梯赛篇(五)---- 难题篇一(30分题目)

数据结构类型

L3-002 特殊堆栈(树状数组)

题目链接

题目大意
本题的难点是维护一个动态的中值。

解题思路
因为值可能是不按大小顺序给出的,因此我们无法利用优先队列来维护,原因是在进行pop的时候可能弹出的是下边或者中间的值,而不是优先队列顶部的值。对于中值,我们对于每一个值如果出现一次,那么其次数加1,那么中值就转变为了这个次数序列中出现次数的中值(因为这个序列是单调的),那么可以单点修改与单点查询的数据结构,就是树状数组了。

  • 对于求中值,我们可以在0 ~ N 中进行二分。

代码:

#include<iostream>
#include<string>
#include<stack>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int t[N];
stack<int>st;
int n ,x;

int lowbit(int x){
   
    return x & -x; }

void add(int k , int v){
   
   
    for( ; k < N ; k += lowbit(k)) t[k] += v;
}

int get(int n){
   
   
    int ans = 0;
    for( ; n ; n -= lowbit(n))ans += t[n];
    return ans;
}

int PeekMedian(){
   
   
    int l = 1 , k = (st.size() + 1)/2 , r = N - 1;
    while(l < r){
   
   
        int mid = (l + r)>>1;
        if(get(mid) >= k) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main(){
   
   
    cin>>n;
    while(n--){
   
   
        string s;
        cin>>s;
        if(s == "Pop"){
   
   
            if(st.size() == 0)cout<<"Invalid\n";
            else{
   
   
                x = st.top();
                cout<<st.top()<<endl;
                st.pop() , add(x , -1);
            }
        }else if(s == "Push"){
   
   
            cin>>x;
            st.push(x) ,add(x,1);
        }else{
   
   
            if(st.size() == 0)cout<<"Invalid\n";
            else cout<<PeekMedian()<<endl;
        }
    }
    return 0;
}

L3-003 社交集群(并查集)

题目链接

题目大意
题目是给出了每一个人的兴趣的编号的集合,对于存在一个兴趣相同的人我们认为其在一个圈子中。然后问你有多少兴趣圈,与每一个圈子有多少人。

解题思路
对于每一个人我们存下,其兴趣圈中的一个代表元素(不妨是第一个元素),之后将其兴趣圈中的所有值进行合并。对于没一个人都这样操作以后。我们枚举这n个人,我们

代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1100;

int p[N];
char ch;
int n , f[N];
int pos[N] ,cnt , p[N];

bool cmp(int a, int b){
   
   return a > b;}

void  init(){
   
   
    for(int i = 1 ;i  < N ; ++i) f[i] = i;
}

int find(int x){
   
   
    if(x == f[x])return x;
    else return f[x] = find(f[x]);
}

void join(int x,int y){
   
   
    x = find(x) , y = find(y);
    if(x != y)f[x] = y;
}

int main(){
   
   
    cin>>n;
    init();
    for(int i = 1 ; i <= n ; ++i){
   
   
        int k , y ;
        cin>>k>>ch;
        for(int j = 1 ;j <= k ; ++j){
   
   
            int x;
            cin>>x;
            if(j == 1)y = x , p[i] = y;
            else join(x ,y);
        }
    }
    for(int i = 1; i <= n ; ++i)
    {
   
   
         int x = find(p[i]);
         pos[x] ++;
     }
    sort(pos ,pos + N , cmp);
    for(int i =
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值