ZOJ 3953 贪心+优先队列

Intervals

Time Limit: 1 Second       Memory Limit: 65536 KB       Special Judge

Chiaki has n intervals and the i-th of them is [liri]. She wants to delete some intervals so that there does not exist three intervals ab and c such that a intersects with bb intersects with c and cintersects with a.

Chiaki is interested in the minimum number of intervals which need to be deleted.

Note that interval a intersects with interval b if there exists a real number x such that la ≤ x ≤ ra and lb ≤ x ≤ rb.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1 ≤ n ≤ 50000) -- the number of intervals.

Each of the following n lines contains two integers li and ri (1 ≤ li < ri ≤ 109) denoting the i-th interval. Note that for every 1 ≤ i < j ≤ nli ≠ lj or ri ≠ rj.

It is guaranteed that the sum of all n does not exceed 500000.

Output

For each test case, output an integer m denoting the minimum number of deletions. Then in the next line, output m integers in increasing order denoting the index of the intervals to be deleted. If mequals to 0, you should output an empty line in the second line.

Sample Input
1
11
2 5
4 7
3 9
6 11
1 12
10 15
8 17
13 18
16 20
14 21
19 22
Sample Output
4
3 5 7 10


题意:给出n个区间,求至少删掉多少个区间使得不存在区间a, b, c 两两相交
(定义两个区间相交是,区间[l1, r1]和区间[l2, r2]相交,当且仅当存在一个数x,l1<=x<=r1 且 l2<=x<=r2)


题解:先离散化一下  然后对于每个点  先把起点在这个点的线段扔到优先队列里面

如果当前点被二个以上的线段覆盖  就把y最远的那条线段拿出来删掉

用mix记录当前点被多少线段覆盖  dd数组代表每条线段在哪里结束

具体细节请读者自行思考

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int dd[100005],num[100005],cnt;
struct node{
    int x,y,lab;
    bool operator <(const node& a)const{
        return y<a.y;
    }
}e[50005];
vector<int>ans;
priority_queue<node,vector<node>,less<node> >sp;
bool cmp(node a,node b){
    return a.x<b.x;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,i,j;
        scanf("%d",&n);
        memset(dd,0,sizeof(dd));
        cnt=0;
        for(i=1;i<=n;i++){
            scanf("%d%d",&e[i].x,&e[i].y);
            e[i].lab=i;
            num[++cnt]=e[i].x;
            num[++cnt]=e[i].y;
        }
        sort(e+1,e+1+n,cmp);
        int mix=0;
        sort(num+1,num+1+cnt);
        cnt=unique(num+1,num+1+cnt)-num-1;
        for(i=1;i<=n;i++){
            e[i].x=lower_bound(num+1,num+1+cnt,e[i].x)-num;
            e[i].y=lower_bound(num+1,num+1+cnt,e[i].y)-num;
        }
        e[n+1].x=-111;
        int now=1;
        while(!sp.empty())sp.pop();
        ans.clear();
        for(i=1;i<=cnt;i++){
            while(e[now].x==i){
                sp.push(e[now]);
                mix++;
                dd[e[now].y+1]--;
                now++;
            }
            mix+=dd[i];
            while(mix>=3){
                node f=sp.top();
                sp.pop();
                mix--;
                dd[f.y+1]++;
                ans.push_back(f.lab);
            }
        }
        sort(ans.begin(),ans.end());
        int dt=ans.size();
        printf("%d\n",dt);
        for(i=0;i<dt;i++){
            printf("%d",ans[i]);
            if(i==dt-1)break;
            else printf(" ");
        }
        printf("\n");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值