zoj3953 Intervals 最大不重叠区间加强版 zoj排名第一~

时间:2021-02-09 08:31:43

Intervals


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

Chiaki has n intervals and thei-th of them is [li,ri]. She wants to delete some intervals so that there does not exist three intervalsa,b andc such thata intersects withb,b intersects withc andc intersects witha.

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

Note that interval a intersects with intervalb if there exists a real numberx such thatlaxra andlbxrb.

Input

There are multiple test cases. The first line of input contains an integerT, 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 integersli andri (1 ≤li <ri ≤ 109) denoting thei-th interval. Note that for every 1 ≤i <jn,lilj orrirj.

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, outputm integers in increasing order denoting the index of the intervals to be deleted. Ifm equals 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

Author: LIN, Xi
Source: The 17th Zhejiang University Programming Contest Sponsored by TuSimple

1,根据数据应该猜到是O(N)或者O(Nlgn)的复杂度解决为题。即区间扫描类型。

2,很容易想到贪心模型中的工作选择问题(最大不重叠区间数)。

3,排序后判断,具体有两种方法。

(1)排序加+线段树(或者BIT)(每加入一个区间前只需要判断L到R的最大值是否‘合格’)。

具体的:按照R从小到大排序之后逐个检查,如果L,R最大值不超过2,那么就把这个区间放进去,区间+1,否则不能放进去。

然后,区间线段树区间处理可以用lazy加以标记。当然也可以离散的树状数组,虽然BIT写起来简单一些,不过加离散化也麻烦,所以将就用线段树。)

(2)排序+贪心,思想和最大不重叠区间数类似。

(1)方法比较好想,不想写代码。点击打开链接

(2)时间和代码上上更加优化。

//本人代码,禁止不思考就引用或者提交。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int N,ans,fin[50030];
struct in{
int L,R,num;
} s[50030]; bool cmp(in a,in b){
return a.R<b.R;
}
void _in()
{
scanf("%d",&N);
for(int i=1;i<=N;i++){
scanf("%d%d",&s[i].L,&s[i].R);
s[i].num=i;
}
}
void _solve()
{
int Fro=0,Now=1,i;
sort(s+1,s+N+1,cmp);
for(i=2;i<=N;i++){
if(s[i].L>s[Now].R) Now=i;
else if(s[i].L>s[Fro].R) {Fro=Now;Now=i;}
else fin[++ans]=s[i].num;
}
printf("%d\n",ans);
sort(fin+1,fin+ans+1);//答案需要排序,我tm找了半天错。。。
for(int j=1;j<=ans;j++)
printf("%d ",fin[j]);
printf("\n");
}
int main()
{
int t,T;
cin>>T;
while(T--){
ans=0;//有计数器,所以不必update
_in();
_solve();
}
return 0;
}