这题有点强,一句话题意:求字典序最小的线段覆盖(这里的字典序指选择的线段的编号排序后的字典序)。
如果不要求字典序只需要对左(右)端点排序,然后贪心取即可。
一开始我想到的是DP,但是字典序存在了不可避免的后效性,看了题解之后,才有了思路。
先离散,要使字典序最小优先选序号小的,然后判断选取某一个之后最优解是否改变。接下来就是怎么O(logn)求区间内线段覆盖。(具体做法搜索ppt。。。
随随便便求出每个点出发走过一条线段之后右端点的最小值,倍增出每个点出发走2^k条线段后的右端点的最小值。每次询问就在倍增的东西上走就好了。
//为了这题学了树状数组区间加,区间查和在树状数组上二分,然而似乎比线段树还慢。。。
注意去掉行末空格
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 400005
using namespace std;
//%%% liang ye
int n,m,cnt,b[N],c[N],p[N],f[N][19],M;
struct T
{
int l,r;
}a[N];
int read()
{
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
void mdy(int x,int k)
{
int t=k*(m-x+1);
for (int i=x;i<=m;i+=i&-i)
b[i]+=t,c[i]+=k;
}
int qry(int x)
{
int t1=0,t2=0;
for (int i=x;i;i-=i&-i)
t1+=b[i],t2+=c[i];
return t1-t2*(m-x);
}
int kth(int x)
{
int t=0,rk=0,tmp,bt=0,ct=0,tt;
for (int i=M;i>=0;i--)
{
tmp=t+(1<<i);
if (tmp>m) continue;
tt=rk+b[tmp]-c[tmp]*(m-tmp)+ct*(tmp-t);
if (tt<x)
rk=tt,t=tmp,bt+=b[tmp],ct+=c[tmp];
}
return t+1;
}
int find(int x)
{
int l=1,r=m,mid;
while(l<=r)
{
mid=l+r>>1;
if (p[mid]==x) return mid;
if (p[mid]<x) l=mid+1;
else r=mid-1;
}
}
void Pre()
{
sort(p+1,p+cnt+1);
for (int i=1;i<=cnt;i++)
if (i==1||p[i]!=p[m]) p[++m]=p[i];
for (;1<<M+1<m;M++);
//M=20;
for (int i=1;i<=n;i++)
{
a[i].l=find(a[i].l);
a[i].r=find(a[i].r);
}
memset(f,0x3f,sizeof f);
for (int i=1;i<=cnt;i++)
f[a[i].l][0]=min(f[a[i].l][0],a[i].r);
for (int i=m-1;i;i--)
f[i][0]=min(f[i][0],f[i+1][0]);
for (int i=1;(1<<i)<m;i++)
for (int j=1;j<=m;j++)
if (f[j][i-1]<m)
f[j][i]=f[f[j][i-1]+1][i-1];
}
int Get(int x,int y)
{
int t=0;
for (int i=M;i>=0;i--)
if (f[x][i]<=y) t+=1<<i,x=f[x][i]+1;
return t;
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read();
for (int i=1;i<=n;i++)
{
a[i].l=read();
a[i].r=read();
p[++cnt]=a[i].l;
p[++cnt]=a[i].r;
}
Pre();
int lych=Get(1,m),hz=0;
printf("%d\n",lych);
for (int i=1;i<=n;i++)
{
int L=qry(a[i].l-1),R=qry(a[i].r);
if (L!=R) continue;
L=L?kth(L)+1:1;
R=R!=qry(m)?kth(R+1)-1:m;
if (Get(L,a[i].l-1)+Get(a[i].r+1,R)+1==Get(L,R))
{
hz++;
printf("%d",i);
if (hz!=lych) putchar(' ');
mdy(a[i].l,1);
mdy(a[i].r+1,-1);
}
}
}