(第九届图灵杯K题金牌厨师)差分维护当前位置连续大于len的区间(二分+差分)

输入样例:

5 5
3 5
1 2
2 5
2 5
4 5

输出样例:

3

可以发现答案是满足用二分来快速寻找答案的.至于证明,这里不予以证明.

关键的问题在于判断在二分中的答案判断其正确性.

假设检验的答案是x.如果能找到至少x个区间的交集元素数量一定是大于等于x,那么x答案就是正确的.由于区间是连续的,所以交集的数也一定是连续的.

那么问题就变为对于一个确定的区间,求出包含这个区间的普通区间数.用差分来维护这个数量.

通过差分数组a来维护当前位置是否存在连续大于len的区间,我们枚举每一个区间的左端点l,如果长度line≥len,我们就在a[l+len-1]加一,a[r+1]减一,表示当前区间内存在连续大于len的区间贡献一下.

最后求一个前缀,如果在1~n中存在某个点前缀和大≥x,那么就说明了x的正确性.

代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn=3e5+50;
int n,m;
int a[maxn];
struct Range
{
    int l,r;
}range[maxn];
int lowbit(int x){
    return x&(-x);
}
void add(int pos,int x){
    while(pos<=n){
        a[pos]+=x;
        pos+=lowbit(pos);
    }
}
int query(int pos){
    int res=0;
    while(pos){
        res+=a[pos];
        pos-=lowbit(pos);
    }
    return res;
}
bool judge(int x){
    memset(a,0,sizeof(a));
    for(int i=1;i<=m;i++){
        if(range[i].r-range[i].l+1>=x){
            add(range[i].l+x-1,1);
            add(range[i].r+1,-1);
        }
    }
    int num=0;
    for(int i=1;i<=n;i++){
        if(query(i)>=x) return true;
    }
    return false;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>range[i].l>>range[i].r;
    }
    int l=1,r=n,ans;
    while(l<=r){
        int mid=l+r>>1;
        if(judge(mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值