题意
给定一些区间,要求删除一些区间使得任意取三个区间不会出现两两相交的情况
思路
先将区间按左端点从小到大排序,遇到出现三个区间两两相交的情况时,显然删掉最靠右的区间会比删掉其他两个更优
如何判断当前有三个区间两两相交呢?
(参考同学的思路)我们可以维护一个缓冲区间,区间里的元素按照右端点从大到小排序,如果新的区间的左端点大于区间最后一个元素的右端点,因为是按照左端点排序扫描的,那么就不用再考虑最后一个元素。当区间中元素有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;
}