Luogu P3602 Koishi Loves Segments

传送门

题解

既然是选取区间,没说顺序
肯定先排遍序 都是套路
那么按什么排序呢???
为了方便处理
我们把区间按左端点从小到大排序
把关键点也按从小到大排序
假设当扫到 \(i\) 点时,i 点之前的点都已处理完毕 (已达上限,或是覆盖了的区间全部取了)
既然要选的区间多
所以需要选的区间对后面的影响少,所以把所有覆盖了当前关键点按右端点从小到大依次选取,直至上限满了为止
这个 用set就解决了
不过一定要记得把右端点小于当前关键点的区间弹掉

代码

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define in inline
#define get getchar()
in int read()
{
    int t=0,x=1; char ch=get;
    while ((ch<'0' || ch>'9') &&ch!='-') ch=get;
    if(ch=='-') ch=get,x=-1;
    while (ch<='9' && ch>='0') t=t*10+ch-'0',ch=get;
    return t*x;
}
const int _=4e5+5;
struct region1{
    int l,r;
}e[_]; //区间
struct drop1{
    int num,a;
}d[_]; //关键点
int n,m;

in int cmp1(drop1 a,drop1 b){return a.num<b.num;}
in int cmp2(region1 a,region1 b){return a.l<b.l;}
bool operator< (const region1 &a,const region1 &b)
{   return a.r<b.r;  }

multiset<region1> s; //可重set
int main()
{
    n=read(),m=read();
    int ans=n;
    for(re int i=1;i<=n;i++)
    {
        e[i].l=read(),e[i].r=read();
        if(e[i].l>e[i].r)swap(e[i].l,e[i].r);
    }
    for(re int i=1;i<=m;i++)
        d[i].num=read(),d[i].a=read();
    sort(d+1,d+1+m,cmp1);
    sort(e+1,e+n+1,cmp2);
    int j=1;
    for(re int i=1;i<=m;i++)
    {
        while (j<=n&&e[j].l<=d[i].num) s.insert(e[j++]); //添加覆盖当前关键点的区间
        while (s.size()!=0 && (*s.begin()).r<d[i].num) s.erase(s.begin()); //去掉右端点已经在当前关键点左侧的区间
        while (s.size()>d[i].a)
        {
            s.erase(--s.end()); // 依次贪心选取可利用的区间
            ans--;
        }
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/yzhx/p/10655218.html