ZOJ 3953 Intervals (贪心/区间交)

题意

给定一些区间,要求删除一些区间使得任意取三个区间不会出现两两相交的情况

思路

先将区间按左端点从小到大排序,遇到出现三个区间两两相交的情况时,显然删掉最靠右的区间会比删掉其他两个更优
如何判断当前有三个区间两两相交呢?
(参考同学的思路)我们可以维护一个缓冲区间,区间里的元素按照右端点从大到小排序,如果新的区间的左端点大于区间最后一个元素的右端点,因为是按照左端点排序扫描的,那么就不用再考虑最后一个元素。当区间中元素有3个时,就可以确定这3个区间两两相交(只要是新加入缓冲区的区间,一定和之前在的区间相交,因为大于之前所有区间的左端点,小于最小的右端点)

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
const int INF=0x3f3f3f3f;
const int maxn=5e4+50;
const int mod=1e9+7;
#define pii pair<int,int>
typedef long long ll;
typedef unsigned int ui;
using namespace std;
struct Node{
    int id,l,r;
    bool operator<(const Node &rhs)const{
        if(l!=rhs.l) return l<rhs.l;
        return r<rhs.r;
    }
};
int n;
Node s[maxn];

bool cmpRG(const Node&a,const Node&b){
    return a.r>b.r;
}
bool cmpRB(const Node&a,const Node&b){
    return a.r<b.r;
}
int main()
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
#endif

    int T; scanf("%d",&T);

    while(T--){
        scanf("%d",&n);
        rep(i,0,n){
            s[i].id=i+1;
            scanf("%d %d",&s[i].l,&s[i].r);
        }
        sort(s,s+n);
        vector<int> ans;
        Node buf[3];
        int pos=0;
        rep(i,0,n){
            //printf("%d %d %d\n",s[i].id,s[i].l,s[i].r);
            sort(buf,buf+pos,cmpRG);
            if(pos && buf[pos-1].r<s[i].l) pos--;
            buf[pos++]=s[i];
            if(pos==3){
                sort(buf,buf+pos,cmpRB);
                ans.push_back(buf[2].id);
                pos--;
            }
        }
        sort(ans.begin(),ans.end());
        printf("%d\n",ans.size());
        for(int i=0;i<ans.size();i++){
            if(i==0) printf("%d",ans[i]);
            else printf(" %d",ans[i]);
        }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值