CF1557D Ezzat and Grid 解题报告

首先把 \(l,r\) 离散化掉,注意数组大小。

\(f_i\) 表示以第 \(i\) 行结尾,能保留的最大行数,\(f_i=\max\{f_j\}+1\),其中 \(i\)\(j\) 存在一个相同位置都被覆盖。

更进一步地,设 \(g_i\) 表示位置 \(i\) 上被线段覆盖时的最大的 \(f\) 值,那么 \(f_i\) 就等于所有第 \(i\) 行线段对应区间的 \(g\) 值的 \(\max\) 再加一,然后把 \(f_i\) 贡献到它对应的区间上,这个贡献直观感受是让区间对 \(f_i\)\(\max\)

但不难发现对于一个 \(i\),每次更新时 \(g_i\) 是单调递增的,即如果这个位置 \(i\)\(f_j\) 更新时被涉及,那么有 \(f_j>g_i\),所以实际上区间取 \(\max\) 的操作改为区间赋值即可。

需要用线段树实现区间赋值,区间查询 \(\max\),方案的话把结点记录的信息改为 pair 即可。

#include<bits/stdc++.h>
using namespace std;
int n,m;
#define mp make_pair
vector<pair<int,int>> Col[300005];
int C[300005],L[300005],R[300005],b[600005],pre[300005];
bool vis[300005];
pair<int,int> maxn[10800005],tag[10800005];
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define Mm int mid=(l+r)>>1
pair<int,int> Max(pair<int,int> x,pair<int,int> y)
{
	if(x.first>y.first)	return x;
	return y;
}
void push_down(int now)
{
	tag[lc(now)]=Max(tag[lc(now)],tag[now]);
	tag[rc(now)]=Max(tag[rc(now)],tag[now]);
	maxn[lc(now)]=Max(maxn[lc(now)],tag[now]);
	maxn[rc(now)]=Max(maxn[rc(now)],tag[now]);
	tag[now].first=0;
}
void push_up(int now){maxn[now]=Max(maxn[lc(now)],maxn[rc(now)]);}
void modify(int l,int r,int now,int x,int y,pair<int,int> val)
{
	if(x<=l && r<=y)
	{
		tag[now]=Max(tag[now],val);
		maxn[now]=Max(maxn[now],val);
		return ;
	}
	push_down(now);
	Mm;
	if(x<=mid)	modify(l,mid,lc(now),x,y,val);
	if(mid<y)	modify(mid+1,r,rc(now),x,y,val);
	push_up(now);
}
pair<int,int> query(int l,int r,int now,int x,int y)
{
	if(x<=l && r<=y)	return maxn[now];
	push_down(now);
	Mm;
	pair<int,int> ret;
	ret.first=0;
	if(x<=mid)	ret=max(ret,query(l,mid,lc(now),x,y));
	if(mid<y)	ret=max(ret,query(mid+1,r,rc(now),x,y));
	return ret;
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d %d %d",&C[i],&L[i],&R[i]);
		b[i*2-1]=L[i],b[i*2]=R[i];
	}
	sort(b+1,b+1+m+m);
	int len=unique(b+1,b+1+m+m)-b-1;
	for(int i=1;i<=m;++i)
	{
		L[i]=lower_bound(b+1,b+1+len,L[i])-b;
		R[i]=lower_bound(b+1,b+1+len,R[i])-b;
		Col[C[i]].push_back(mp(L[i],R[i]));
	}
	for(int i=1;i<=n;++i)
	{
		int dp=0;
		for(auto st:Col[i])	dp=max(dp,query(1,len,1,st.first,st.second).first);
		for(auto st:Col[i])
		{
			pair<int,int> que=query(1,len,1,st.first,st.second);
			if(que.first==dp)
			{
				pre[i]=que.second;
				break;
			}
		}
		++dp;
		for(auto st:Col[i])	modify(1,len,1,st.first,st.second,mp(dp,i));
	}
	printf("%d\n",n-maxn[1].first);
	int now=maxn[1].second;
	while(now)
	{
		vis[now]=true;
		now=pre[now];
	}
	for(int i=1;i<=n;++i)	if(!vis[i])	printf("%d ",i);
	return 0;
}
posted @ 2026-06-04 15:21  Luowj  阅读(8)  评论(0)    收藏  举报