CF1405E Fixed Point Removal(线段树+二分)

第一点可以想到的是,对于某个位置i上的数,他能不能被删除只和前面的数的能不能删除掉-(a[i]-i)的数有关。前提是他要a[i]-i小于0

现在的问题是,因为他有很多询问,因为左区间的限定,我们对每个询问需要知道每个i对于当前左区间l-i之间能删除多少个数,这样我们才能知道对于当前区间这个点能不能删除。

因此我们想到每个左区间的端点都是十分重要的,因此我们考虑维护一个线段树,每个点的意义都是以i为左区间能删除的数的大小。

对于每个点,我们在线段树上二分查询到离他最近的能满足条件的位置,把点的贡献加到对应位置上,这样做是最优的。

另外,这需要对询问排序,因为我们不能让后面的点对当前位置的答案产生错误的贡献

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n,q;
int a[N];
struct Q{
    int l,r;
    int id;
}s[N];
struct node{
    int l,r;
    int sum;
}tr[N<<2];
bool cmp(Q a,Q b){
    return a.r>b.r;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r,0};
    }
    else{
        tr[u]={l,r,0};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
    }
}
void modify(int u,int l,int x){
    if(tr[u].l==tr[u].r){
        tr[u].sum+=x;
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,x);
    else
        modify(u<<1|1,l,x);
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
int query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].sum;
    }
    int mid=tr[u].l+tr[u].r>>1;
    int ans=0;
    if(l<=mid){
        ans+=query(u<<1,l,r);
    }
    if(r>mid)
        ans+=query(u<<1|1,l,r);
    return ans;
}
int ans[N];
int get(int u,int l){
    if(tr[u].l==tr[u].r){
        return tr[u].l;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(tr[u<<1|1].sum>=l){
        return get(u<<1|1,l);
    }
    else{
        return get(u<<1,l-tr[u<<1|1].sum);
    }
}
int main(){
    cin>>n>>q;
    int i;
    for(i=1;i<=n;i++){
        cin>>a[i];
        a[i]-=i;
    }
    for(i=1;i<=q;i++){
        int x,y;
        cin>>x>>y;
        s[i]={x,y,i};
    }
    sort(s+1,s+1+q,cmp);
    int cur=1;
    int tot=0;
    build(1,1,n);
    for(i=1;i<=q;i++){
        while(cur<=n-s[i].r){
            if(a[cur]==0)
                modify(1,cur,1),tot++;
            else if(a[cur]<0&&-a[cur]<=tot){
                modify(1,get(1,-a[cur]),1);
                tot++;
            }
            cur++;
        }
        ans[s[i].id]=query(1,s[i].l+1,n-s[i].r);
    }
    for(i=1;i<=q;i++)
        cout<<ans[i]<<endl;
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13761510.html