• E


    题:https://codeforces.com/problemset/problem/1404/C

    题意:给定n个数的序列,每次可将下标==权值的位置remove,剩下的俩个区间则合并在一起。q个询问区间问[l+1,n-r]最多能删去多少个。

    分析:前面的点对后面的位置有影响,所以先将查询离线起来按r来排序,查询就以枚举的r为右边界来记录答案;

       操作ai=i-ai,remove就是删除ai==0的位置,定义f(l ,r)为区间[l,r]最多能删除多少个数;

       对于当前枚举的r,若a[i]>=0,找到最大的l:lmax满足f(lmax,r)>=a[i],然后就在[1,lmax]+1,代表若查询区间的右端点r,左端点在[1,lmax]内的答案贡献加1(因为依据二分查询的[lmax,r]区间内已经有a[i]个数可remove来使a[i]能remove);

       而f(l,r)则用BIT维护,可以保证f(1,r),f(2,r),f(3,r),...为单调不降的。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define MP make_pair
    #define pii pair<int,int>
    typedef long long ll;
    const int mod=1e9+7;
    const int M=1e6+6;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    int a[M],ans[M],n,q;
    vector<pii >v[M];
    struct BIT{
        int tr[M];
        void init(){
            memset(tr,0,sizeof(tr));
        }
        void add(int i,int x){
            while(i<=n)
                tr[i]+=x,i+=i&(-i);
        }
        int sum(int i){
            int res=0;
            while(i){
                res+=tr[i];
                i-=i&(-i);
            }
            return res;
        }
    }t1;
    int main(){
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]=i-a[i];
        }
        for(int i=1;i<=q;i++){
            int l,r;
            scanf("%d%d",&l,&r);
            l=l+1,r=n-r;
            v[r].pb(MP(l,i));
        }
        t1.init();
        for(int i=1;i<=n;i++){
            if(a[i]>=0){
                int l=1,r=i,pos=0;
                while(l<=r){
                    int midd=(l+r)>>1;
                    if(t1.sum(midd)>=a[i]){
                        l=midd+1;
                        pos=midd;
                    }
                    else
                        r=midd-1;
                }
                if(pos){
                    t1.add(1,1);
                    t1.add(pos+1,-1);
                }
            }
            for(auto it:v[i]){
                int l=it.first,id=it.second;
                ans[id]=t1.sum(l);
            }
        }
        for(int i=1;i<=q;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    哪些人需要学习Python开发?
    爬虫为什么用python
    python序列类型包括哪三种
    学习python的五个特点
    学python安装软件推荐
    怎么用python做网站?
    为什么大家都说,人生苦短我用python
    #专题练习# 搜索
    #专题练习# 网络流
    #专题练习# 强连通分量,缩点
  • 原文地址:https://www.cnblogs.com/starve/p/13632285.html
Copyright © 2020-2023  润新知