Codeforces Round #737 (Div. 2) Ezzat and Grid(线段树优化dp)

题目地址Ezzat and Grid
Moamen was drawing a grid of n rows and 109 columns containing only digits 0 and 1. Ezzat noticed what Moamen was drawing and became interested in the minimum number of rows one needs to remove to make the grid beautiful.

A grid is beautiful if and only if for every two consecutive rows there is at least one column containing 1 in these two rows.

Ezzat will give you the number of rows n, and m segments of the grid that contain digits 1. Every segment is represented with three integers i, l, and r, where i represents the row number, and l and r represent the first and the last column of the segment in that row.

For example, if n=3, m=6, and the segments are (1,1,1), (1,7,8), (2,7,7), (2,15,15), (3,1,1), (3,15,15), then the grid is:
在这里插入图片描述
Your task is to tell Ezzat the minimum number of rows that should be removed to make the grid beautiful.

思路:dp[i][j] 为 i 行之前删除一些行之后满足条件的最大行数, j为这一行中有1的状态
要寻找当前行中满足条件的最大行数 如果当前行中有1的状态和前面行中有1的状态相交 ,当前行=前面与当前1相交的行的最大值 +1
可以用线段树维护区间最大值

#include<bits/stdc++.h>
//#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
//const int inf=2e18+100;
const int maxn=1e6+100;
typedef pair<int,int> pii;
struct node//线段树维护区间最大值,顺便保存行号; 
{
   int l,r;
   pii sum;
   pii lazy;
   //int c;
} t[maxn*4];
struct node1
{
   int c,l,r;
} t1[maxn];
vector<pii>g[maxn];
pii Max(pii a,pii b)
{
   if(a.first>b.first)return a;
   return b;
}
void pushup(int k)
{
   t[k].sum=Max(t[k<<1].sum,t[k<<1|1].sum);
}
void pushdown(int k)
{
   if(t[k].lazy.first)
   {
   	t[k<<1|1].lazy=t[k].lazy;
   	t[k<<1].lazy=t[k].lazy;
   	t[k<<1|1].sum=t[k].lazy;
   	t[k<<1].sum=t[k].lazy;
   	t[k].lazy={0,0};
   }
}
void build(int k,int l,int r)
{
   t[k].l=l;
   t[k].r=r;
   if(l==r)return ;
   int mid=(l+r)>>1;
   build(k<<1,l,mid);
   build(k<<1|1,mid+1,r);
   pushup(k);
}
void update(int l,int r,int k,pii p)
{
   if(l>t[k].r||r<t[k].l)return ;
   if(l<=t[k].l&&t[k].r<=r)
   {
   	t[k].sum=p;
   	t[k].lazy=p;
   	return ;
   }
   pushdown(k);
   update(l,r,k<<1,p);
   update(l,r,k<<1|1,p);
   pushup(k);
}
pii query(int l,int r,int k)
{
   if(r<t[k].l||l>t[k].r)return {0,0};
   if(l<=t[k].l&&t[k].r<=r)
   {
   	return t[k].sum;
   }
   pushdown(k);
   return Max(query(l,r,k<<1|1),query(l,r,k<<1));
}
map<int,int>mp;
int pre[maxn];//保存前驱 
bool vis[maxn];
signed main()
{
   IOS
   int n,m;
   cin>>n>>m;
   for(int i=1; i<=m; i++)
   {
   	int c,l,r;
   	cin>>c>>l>>r;
   	mp[l]=1;
   	mp[r]=1;
   	t1[i]= {c,l,r};
   }
   int k=0;
   for(auto it:mp)
   {
   	mp[it.first]=++k;//离散化 
   }
   build(1,1,k);
   for(int i=1; i<=m; i++)
   {
   	int x=mp[t1[i].l];
   	int y=mp[t1[i].r];
   	g[t1[i].c].push_back({x,y});
   }
   int ans=0,fg=0;//最大的值和取得最大值的行 
   for(int i=1; i<=n; i++)
   {
   	int now=-1;
   	for(auto it:g[i])
   	{
   		pii p=query(it.first,it.second,1);//查询i之前该区间的最大值 
   		if(p.first>now)
   		{
   			now=p.first;
   			pre[i]=p.second;
   		}
   	}
   	if(now+1>ans)//更新最大值 
   	{
   		ans=now+1;
   		fg=i;
   	}
   	for(auto it:g[i])
   	{
   		update(it.first,it.second,1, {now+1,i});//更新i行的区间 
   	}
   }
   cout<<n-ans<<"\n";
   for(int i=fg; i != 0; i = pre[i]) vis[i] = 1;
   for(int i=1; i<=n; i++)
   {
   	if(vis[i]==0)
   	{
   		cout<<i<<" ";
   	}
   }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

thusloop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值