[EOJ]2019 ECNU XCPC March Selection #1 F

题意:数轴上有n个点,m条线段,选出尽量多的线段,使每条线段都能独立地占有至少一个点(不可公用同一个点)。

线段覆盖问题,按右端点升序,右端点相同时左端点降序排序,画图可以看出前边的线段应该尽量用前边的点,把点排序,依此对每条线段二分查找可以用的点。

(考场上开始没想清楚,用左端点做了第一关键字,后来好好画图很容易看出来应该用右端点做第一关键字)

比较典型的一道题。

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


typedef long long LL ;

#define rep(i,n) for(int i=1;i<=n;i++)
#define pb push_back
#define st first
#define nd second
#define mp make_pair
#define pii pair<int ,int >

const int N = 2e4+7;
const int MX = 1e9+7;

int t[N],n,m,tag[N];

pii a[N];

int cmp(pii a,pii b){
    if(a.nd!=b.nd)return a.nd<b.nd;
    return a.st>b.st;
}

int find(int x){
    int l=1,r=n,ans=n+1;
    while(l<=r){
        int mid=(l+r)/2;
        if(t[mid]>=x){
            ans=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    return ans;
}

int main(){
    scanf("%d%d",&n,&m);
    rep(i,n)scanf("%d",&t[i]);
    rep(i,m)scanf("%d%d",&a[i].st,&a[i].nd);
    sort(t+1,t+1+n);
    sort(a+1,a+1+m,cmp);
    int ans=0;
    rep(i,m){
        int x=find(a[i].st);
        while(tag[x]&&x<=n)x++;
        if(x==n+1)continue;
        if(a[i].nd>=t[x]){
            ans++;
            tag[x]=1;
        }
    }
    cout<<ans;
} 
原文地址:https://www.cnblogs.com/xutianshu/p/10459497.html