LINK

定义 f [ i ] f[i] f[i]表示以第 i i i行结尾,最少删掉的行数

若第 i i i行与第 j j j行有交,有转移

f [ i ] = f [ j ] + ( i − j − 1 ) f[i]=f[j]+(i-j-1) f[i]=f[j]+(ij1)

但是显然不能暴力枚举 j j j,而且判断线段是否有交也得枚举,也是个大问题

考虑 j 1 , j 2 j_1,j_2 j1,j2行都覆盖了点 w w w,下次某一行 i i i如果覆盖了点 w w w,显然是从 j 1 , j 2 j_1,j_2 j1,j2挑一个代价更小的转移而来

然后再注意转移方程,其实可以写成

f [ i ] = ( f [ j ] − j ) + ( i − 1 ) f[i]=(f[j]-j)+(i-1) f[i]=(f[j]j)+(i1)

显然 f [ j ] − j f[j]-j f[j]j看成一个整体,那么对后续的贡献都是相同的

于是容易想到,维护一颗线段树,线段树的叶子节点 w w w表示覆盖 w w w的最优秀的 f [ j ] − j f[j]-j f[j]j

这样,转移 第 i 第i i行的时候,枚举所有线段在区间上取 m i n min min即可

最后枚举以 i i i结尾答案就是需要删掉 f [ i ] + ( n − i ) f[i]+(n-i) f[i]+(ni)(因为后面也需要删掉)

#include <bits/stdc++.h>
using namespace std;
#define se second
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn = 6e5+10;
const int inf = 1e9;
typedef pair<int,int>p;
p now;
vector<p>vec[maxn];
int f[maxn],pre[maxn],ok[maxn],li[maxn],top,z,n,m;
void read()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
	{
		int id,l,r; scanf("%d%d%d",&id,&l,&r);
		vec[id].push_back( {l,r} );
		li[++li[0]] = l, li[++li[0]] = r;
	}
	sort( li+1,li+1+li[0] );
	top = unique( li+1,li+1+li[0] )-li-1;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<vec[i].size();j++)
		{
			vec[i][j].first = lower_bound( li+1,li+1+top,vec[i][j].first )-li;
			vec[i][j].se = lower_bound( li+1,li+1+top,vec[i][j].se )-li;
		}
	}
}
p sum[maxn<<2],laz[maxn<<2];
void pushdown(int rt,int l,int r)
{
	if( laz[rt].first==inf )	return;
	sum[ls] = min( sum[ls],laz[rt] );	sum[rs] = min( sum[rs],laz[rt] );
	laz[ls] = min( laz[ls],laz[rt] );	laz[rs] = min( laz[rs],laz[rt] );
	laz[rt] = {inf,0};
}
void update(int rt,int l,int r,int L,int R,p val)
{
	if( l>R || r<L )	return;
	if( l>=L && r<=R )
	{ 
		sum[rt] = min( sum[rt],val );	laz[rt] = min( laz[rt],val );
		return; 
	}
	pushdown(rt,l,r);
	update( lson,L,R,val ); update( rson,L,R,val );
	sum[rt] = min( sum[ls],sum[rs] );
}
void get(int rt,int l,int r,int L,int R)
{
	if( l>R || r<L )	return;
	if( l>=L && r<=R )	{ now = min( now,sum[rt]); return; }
	pushdown(rt,l,r);
	get( lson,L,R ); get( rson,L,R );
}
void solve()
{
	int mi = inf, id = 0;
	for(int i=1;i<=n;i++)
	{
		if( f[i]+(n-i)<mi )	
			mi = f[i]+(n-i), id = i;
	}
	while( id )	ok[id] = 1, id = pre[id];
	cout << mi << endl;
	for(int i=1;i<=n;i++)
		if( ok[i]==0 )	cout << i << " ";	
}
void DP()
{
	for(int i=1;i<=4*top;i++)	sum[i] = {0,0},laz[i] = {inf,0};
	for(int i=1;i<=n;i++)
	{
		if( vec[i].size()==0 )	{ f[i] = inf; continue; }
		z++;
		now = {inf,0};
		for(auto v:vec[i] )
			get(1,1,top,v.first,v.se );
		f[i] = now.first+i-1, pre[i] = now.second;
		for(auto v:vec[i] )
			update( 1,1,top,v.first,v.se,{ f[i]-i,i } );
	}
}
signed main()
{
	read();
	DP();
	solve();
}