hdu 6695 2019 杭电多校十 1005 Welcome Party

题意:学生有歌唱能力值和相声能力值,每个学生参加歌唱或者相声其中之一,找参加歌唱比赛中歌唱能力值最大的和相声比赛中相声能力值最大的,求其差的绝对值使其最小
比赛的时候处理不了重复数据的问题,就一直划水,看到别人用了个STL解决了这个问题,multiset,可以存储重复数据的集合,他的函数find可以在logn时间内找到需要的值的位置,还附带lower_bound函数可以用,就是注意他的erase函数是删除所有相同元素,比如erase(5),它就把所有5元素删除了,想要删除一个就这样用:earse(find(5))删除第一个找到5的位置
思路:把每个学生数据存好,按歌唱能力从大到小排序,枚举每一个人,假设他为参加歌唱比赛中能力值最突出者,把所有歌唱能力值比他大的人都安排参加相声比赛,并且把他们的相声值存入multi集合 up 中,把所有歌唱能力值比他小的学生的相声能力值存入multi集合 down 中,查找的时候分类讨论一下,把up中的最大值找出来,把down中的最接近当前选手歌唱能力的值找出来(就要用lower_bound),如果up中的最大值比down中的最接近的值大,那么没办法,只能选up中的最大值,因为up中的人所有歌唱能力都比当前枚举到的人高,所以不能让他们回来唱歌,不然就跟我的假设此人歌唱能力最高矛盾了,那如果down中找到的最接近的值比较大,那么就求一次绝对差再比较,不要忘了!!!!!这时候up中的最大值也要求一次绝对差再比较,因为down中的最接近值可能很大很大,而up中最大值反而比较接近此人的歌唱能力。

#include <bits/stdc++.h>
#define eps 1e-14
#define pi acos(-1)
#define ll long long
#define RD T*(rand()*2-RAND_MAX)
#define Drand (long double)rand()/RAND_MAX
#define LINF 0x7f7f7f7f7f7f7f7f
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2e5+10;
const long long mod=1e18;

struct P
{
    ll g,x;
}p[maxn];

int cmp(P a,P b)
{
    return a.g>b.g;
}

int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        multiset<ll>up,down;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&p[i].g,&p[i].x);
            down.insert(p[i].x);
        }
        sort(p+1,p+1+n,cmp);
        ll ans=LINF;
        for(int i=1;i<=n;i++){
            down.erase(down.find(p[i].x));
            if(i>1 && p[i].g!=p[i-1].g){
                for(int j=i-1;j>=1;j--){
                    if(p[j].g==p[i-1].g){
                        down.erase(down.find(p[j].x));
                        up.insert(p[j].x);
                    }
                    else break;
                }
            }
            auto dit=down.lower_bound(p[i].g);
            auto uit=up.end();
            if(up.size()>0)
                uit--;
            if(dit==down.end() && down.size()>0){
                --dit;
            }

            if(up.size()==0){
                auto dit1=dit;
                if(dit!=down.begin())--dit;
                ans=min(ans,min(abs(*dit-p[i].g),abs(*dit1-p[i].g)));
            }
            else if(down.size()==0){
                auto uit1=up.end();
                --uit1;
                ans=min(ans,abs(*uit1-p[i].g));
            }
            else{
                if(*uit<=*dit){
                    auto dit1=dit;
                    if(dit1!=down.begin())dit1--;
                    if(*dit1>*uit)
                        ans=min(ans,abs(*dit1-p[i].g));
                    ans=min(ans,abs(*dit-p[i].g));
                }
                ans=min(ans,abs(*uit-p[i].g));
            }
            down.insert(p[i].x);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值