CF1884C Medium Design
思路
Step1. 贪心
拿到题后,第一时间想到贪心,如果这个区间加上会使答案变小或不变就不加。
但是很显然,这个贪心是错误的。
如果答案的最大值在区间 B,但是先加了区间 A,导致加区间 B 使答案不变,那么这样就会使答案变劣。
所以贪心是错误的。
Step2. 枚举
接着,想到了可以枚举最小值,如果某个区间包含了这个最小值,那么这个区间加上后的答案一定是不优于不加上这个区间的答案,所以所有包含了这个最小值的区间都不需要加,那么再把所有最小值的答案取个最大值即可。
当然了,区间的值大,所以需要离散化。
有个巨佬朋友写过这种做法的题解。
这里就不赘述了。
Step3. 优化
事实上,最小值的选择的讨论是多余的,假设最小值选在 \(x\) 点,那么所有横跨 \(x\) 的区间都是无效的,那么可以对答案做出贡献的只有两个端点都在 \(x\) 左侧或者都在右侧的区间才有用,那么假设最后的最大值在 \(x\) 左侧,那么在 \(x\) 右侧的区间无用,这样的话,把 \(x\) 右移可以让区间变多或不变,那么答案将会变优或者不变,同理最大值在 \(x\) 右侧也可以得到 \(x\) 在左端点不劣。
总而言之就是,如果 \(x\) 选在中间,那么答案一定不优于 \(x\) 选择两端的情况。
所以我们只需要讨论两种情况即可。
所以如果一个区间左端点有 \(1\) 的话,就把这个区间加给第一组线段树。
如果一个区间右端点有 \(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. 进一步优化
可以发现,只需要区间修改和一次区间查询,所以实际上可以直接使用差分数组进行维护,如果不算上离散化要用到的排序的话,时间复杂度更优,代码也更简单。
主要是因为前面的方法需要线段树,所以最开始没想到差分,辛辛苦苦写完了才发现更本不需要。
因为代码难度低,所以这里就不放差分版的代码了 (绝对不是我懒得再写一个差分了)。