线段树,排序。
按照$R$从小到大排序之后逐个检查,如果$L$,$R$最大值不超过$2$,那么就把这个区间放进去,区间$+1$,否则不能放进去。
#include<bits/stdc++.h> using namespace std; int T,n,sz; int a[100010]; struct X { int L,R,id; }s[50010]; int f[400010],m[400010]; int P; bool cmp(X a,X b) { return a.R<b.R; } int get(int x) { int ll=1,rr=sz,res; while(ll<=rr) { int mid = (ll+rr)/2; if(a[mid]>x) rr=mid-1; else if(a[mid]==x) return mid; else ll=mid+1; } } void pushDown(int rt) { if(f[rt]==0) return ; f[2*rt]+=f[rt]; f[2*rt+1]+=f[rt]; m[2*rt]+=f[rt]; m[2*rt+1]+=f[rt]; f[rt]=0; } void update(int L,int R,int val,int l,int r,int rt) { if(L<=l&&r<=R) { f[rt]+=val; m[rt]+=val; return ; } pushDown(rt); int mid = (l+r)/2; if(L<=mid) update(L,R,val,l,mid,2*rt); if(R>mid) update(L,R,val,mid+1,r,2*rt+1); m[rt] = max(m[2*rt],m[2*rt+1]); } void query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { P=max(P,m[rt]); return ; } pushDown(rt); int mid = (l+r)/2; if(L<=mid) query(L,R,l,mid,2*rt); if(R>mid) query(L,R,mid+1,r,2*rt+1); m[rt] = max(m[2*rt],m[2*rt+1]); } void build(int l,int r,int rt) { m[rt] = 0; f[rt] = 0; if(l==r) return ; int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); } int ans[50010],q; int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); sz=0; for(int i=1;i<=n;i++) { scanf("%d%d",&s[i].L,&s[i].R); sz++; a[sz]=s[i].L; sz++; a[sz]=s[i].R; } sort(a+1,a+1+sz); for(int i=1;i<=n;i++) { s[i].L=get(s[i].L); s[i].R=get(s[i].R); s[i].id=i; } sort(s+1,s+1+n,cmp); q=0; build(1,sz,1); for(int i=1;i<=n;i++) { P=0; query(s[i].L,s[i].R,1,sz,1); if(P==2) { ans[q++]=s[i].id; continue; } else update(s[i].L,s[i].R,1,1,sz,1); } sort(ans,ans+q); printf("%d ",q); for(int i=0;i<q;i++) { printf("%d",ans[i]); if(i<q-1) printf(" "); } printf(" "); } return 0; }