CF1884C Medium Design

去洛谷看我的博客

思路

Step1. 贪心

拿到题后,第一时间想到贪心,如果这个区间加上会使答案变小或不变就不加。

但是很显然,这个贪心是错误的。

如果答案的最大值在区间 B,但是先加了区间 A,导致加区间 B 使答案不变,那么这样就会使答案变劣。

所以贪心是错误的。

Step2. 枚举

接着,想到了可以枚举最小值,如果某个区间包含了这个最小值,那么这个区间加上后的答案一定是不优于不加上这个区间的答案,所以所有包含了这个最小值的区间都不需要加,那么再把所有最小值的答案取个最大值即可。

当然了,区间的值大,所以需要离散化。

有个巨佬朋友写过这种做法的题解

这里就不赘述了。

Step3. 优化

事实上,最小值的选择的讨论是多余的,假设最小值选在 x x x 点,那么所有横跨 x x x 的区间都是无效的,那么可以对答案做出贡献的只有两个端点都在 x x x 左侧或者都在右侧的区间才有用,那么假设最后的最大值在 x x x 左侧,那么在 x x x 右侧的区间无用,这样的话,把 x x x 右移可以让区间变多或不变,那么答案将会变优或者不变,同理最大值在 x x x 右侧也可以得到 x x x 在左端点不劣。

总而言之就是,如果 x x x 选在中间,那么答案一定不优于 x x x 选择两端的情况。

所以我们只需要讨论两种情况即可。

所以如果一个区间左端点有 1 1 1 的话,就把这个区间加给第一组线段树。

如果一个区间右端点有 m m m 的话,就把这个区间加给第二组线段树。

注意:一个区间可以加给两个线段树。

那么最后的答案就是两组线段树维护的最大值的较大值。

同样地,需要离散化。

AC code

#include<bits/stdc++.h>
using namespace std;
struct segtree
{
	struct node{int l,r,maxn,tag;}t[800005];
	inline void pushup(int p){t[p].maxn=max(t[p<<1].maxn,t[p<<1|1].maxn);}
	inline void addtag(int p,int k){t[p].maxn+=k,t[p].tag+=k;}
	inline void pushdown(int p){addtag(p<<1,t[p].tag),addtag(p<<1|1,t[p].tag),t[p].tag=0;}
	void build(int p,int l,int r)
	{
		t[p].l=l,t[p].r=r,t[p].maxn=t[p].tag=0;
		if(l==r) return;
		int mid=l+r>>1;
		build(p<<1,l,mid),build(p<<1|1,mid+1,r);
	}
	void update(int p,int l,int r)
	{
		if(t[p].l>=l&&t[p].r<=r){addtag(p,1);return;}
		if(t[p].tag) pushdown(p);
		int mid=t[p].l+t[p].r>>1;
		if(mid>=l) update(p<<1,l,r);
		if(mid<r) update(p<<1|1,l,r);
		pushup(p);
	}
}t1,t2;
int T,n,m,l[200005],r[200005],a[400005],num;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]),a[i*2-1]=l[i],a[i*2]=r[i];a[n*2+1]=1,a[n*2+2]=m;
		sort(a+1,a+2*n+3),num=unique(a+1,a+2*n+3)-a-1;
		t1.build(1,1,num),t2.build(1,1,num);
		//cout<<num<<endl;
		for(int i=1;i<=n;++i)
		{
			l[i]=lower_bound(a+1,a+num+1,l[i])-a,r[i]=lower_bound(a+1,a+num+1,r[i])-a;
			if(l[i]!=1) t1.update(1,l[i],r[i]);
			if(r[i]!=num) t2.update(1,l[i],r[i]);
		}
		printf("%d\n",max(t1.t[1].maxn,t2.t[1].maxn));
	}
	return 0;
}

Step4. 进一步优化

可以发现,只需要区间修改和一次区间查询,所以实际上可以直接使用差分数组进行维护,如果不算上离散化要用到的排序的话,时间复杂度更优,代码也更简单。

主要是因为前面的方法需要线段树,所以最开始没想到差分,辛辛苦苦写完了才发现更本不需要。

因为代码难度低,所以这里就不放差分版的代码了 (绝对不是我懒得再写一个差分了)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值