2020ICPC江西C Charging(二分)

首先观察到答案具有单调性

其次,考虑如何check,一个朴素的想法就是枚举区间,之后判断覆盖这段区间的plan有几个,再取个min

这样做复杂度较高,考虑一下优化。

我们可以枚举右端点,之后把符合条件的左端点用树状数组维护,之后用一个指针去不断往前找到最远的符合覆盖大于二分值的点。

注意,这个指针不要回溯,这样才能保证复杂度,因为这样遍历的次数才是n,否则复杂度随着数据变化,并且这个指针本来就不需要回溯,因为你之前不满足答案,右端点左移,显然更不可能满足答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=3e5+10;
vector<int> num[N];
int tr[N];
int n,m;
int lowbit(int x){
    return x&-x;
}
void add(int x,int c){
    int i;
    for(i=x;i<N;i+=lowbit(i)){
        tr[i]+=c;
    }
}
int sum(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i)){
        res+=tr[i];
    }
    return res;
}
bool check(int mid){
    int i;
    int now=n;
    memset(tr,0,sizeof tr);
    for(i=n;i>=1;i--){
        for(auto x:num[i]){
            add(x,1);
        }
        now=min(now,i);
        if(sum(now)<mid)
            continue;
        while(now>1&&sum(now-1)>=mid)
            now--;
        if(i-now+1>=mid)
            return true;
    }
    return false;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int i;
    for(i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        num[y].push_back(x);
    }
    int l=0,r=min(n,m)+1;
    while(l<r){
        int mid=l+r+1>>1;
        if(check(mid))
            l=mid;
        else
            r=mid-1;
    }
    cout<<l<<endl;
    return 0;
}
View Code

 

posted @ 2020-12-06 15:44  朝暮不思  阅读(157)  评论(0编辑  收藏  举报