Exhausted? 题解(线段树)
Exhausted? 题解
前言:
看本篇题解,您如果想要掌握所有知识点的话,请您先去了解下什么是霍尔定理,当然如果可以的话,可以去看看我的这个博客。
涉及的算法和思想知识点:
- 线段树、扫描线。
- 霍尔定理。
- 较少的容斥原理。
正文:
理论分析:
-
从简单入手:我们想想,要是值域再小一点的话,我们可以怎么做?我的想法是直接把人和合理的区间各个位置连边,形成一个二分图,求解最大匹配找到最多的能不添加椅子就可以做的人,然后用总共的减去就是最小的了。
-
思维拔升:我们发现不可以建立图时,不然就是算法有问题不然就是要用各种理论来简化,对于二分图而言,一般建不了图,就是霍尔定理。我们将人看做
,根据定理,那么我们就是求解 这个柿子。 -
举例化简:现在我们随便选择两个点作为
那么就是求解他们 的并。我们稍微容斥一下,变为求解两个点区间的补集的交集的补集。这么说很混乱,我直接举例子吧,就是求 和 的交集的补集。我们用柿子表达,就是求 。注意下,要是没有交集,答案就是 ,所以答案至少为它。 -
思考解决最值的方向:我们为了让上述柿子最大,像这种题目不然就是贪心,不然就是找函数最值,不然就是硬着头皮想方法维护。贪心的话我实在想不出来,用函数的话,我们会发现我们点选得越多,
却不会变长。两者是“你增加我可能减少”的关系,所以从函数本身来看似乎就不行了。那就只能硬着头皮去维护这个柿子了。
代码实现思路(重点):
因为我觉得维护很难想到,所以专门开了个重点来。
考虑到一个交集的左端点一定是一个原来的左端点之一,右端点同理。于是我现在想找一个左端点确定的交集查找答案(通过枚举线段来确定)。
当这个交集的左端点确定时,我选择的点只能是左端点在它左侧,右端点在他右侧的线段(否则的话交集左端点会变化或者不会有交集)。由于左端点确定,我们假设已经确定这个交集的右端点为
所以最后就是
具体做法是在线段树上把i位置的初值设为i,然后每次将
代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int le;
int ri;
}stu[200005];
bool cmp(node x,node y){
if(x.le!=y.le)return x.le<y.le;
else return x.ri<y.ri;
}
int ans=0;
struct nod{
int le;
int ri;
int val;
int lz;
}tree[800005];
vector<int>h[200005];
void pushup(int rt){
tree[rt].val=max(tree[rt*2].val,tree[rt*2+1].val);
}
void pushdown(int rt){
if(!tree[rt].lz){
return;
}
tree[rt*2].lz+=tree[rt].lz;
tree[rt*2+1].lz+=tree[rt].lz;
tree[rt*2].val+=tree[rt].lz;
tree[rt*2+1].val+=tree[rt].lz;
tree[rt].lz=0;
return;
}
void build(int rt,int L,int R){
tree[rt].le=L;
tree[rt].ri=R;
if(L==R){
tree[rt].val=L;
return;
}
int mid=(L+R)>>1;
build(rt*2,L,mid);
build(rt*2+1,mid+1,R);
pushup(rt);
}
void add(int rt,int L,int R,int v){
int le=tree[rt].le;
int ri=tree[rt].ri;
if(le>=L&&ri<=R){
tree[rt].val+=v;
tree[rt].lz+=v;
return;
}
if(le>R||ri<L){
return;
}
pushdown(rt);
add(rt*2,L,R,v);
add(rt*2+1,L,R,v);
pushup(rt);
}
int get(int rt,int L,int R){
int le=tree[rt].le;
int ri=tree[rt].ri;
if(le>=L&&ri<=R){
return tree[rt].val;
}
if(le>R||ri<L){
return 0;
}
pushdown(rt);
int ret=0;
ret=max(ret,get(rt*2,L,R));
ret=max(ret,get(rt*2+1,L,R));
pushup(rt);
return ret;
}
int main(){
ios::sync_with_stdio(false);
int n,m;
cin >>n >>m;
for(int i=1;i<=n;i++){
cin >> stu[i].le>>stu[i].ri;
h[stu[i].le].push_back(stu[i].ri);
}
ans=max(0,n-m);
build(1,0,m+1);
for(int i=0;i<=m+1;i++){
for(int j=0;j<h[i].size();j++){
int to=h[i][j];
add(1,0,to,1);
}
ans=max(ans,get(1,i+1,m+1)-i-m-1);
}
cout<<ans;
}
本文作者:linghusama
本文链接:https://www.cnblogs.com/linghusama/p/17811380.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步