• CF 1405E Fixed Point Removal【线段树上二分】


    CF 1405E Fixed Point Removal【线段树上二分】 

    题意:

    给定长度为(n)的序列(A),每次操作可以把(A_i = i)(即值等于其下标)的数删掉,然后剩下的数组拼接起来,问最多能删多少个数

    (q)次独立询问,每次把前(x)个数和(后)(y)个数置为(n+1)之后解决上述问题

    题解:

    先不考虑把前(x)个数和后(y)个数置成(n+1)的情况

    首先我们可以想到的是把所有数的值减去其下标,定义(B_i = A_i - i),那么对于(B_i=0)的位置,一开始就是可以删除的,当删掉了第(i)个数之后,之前的数的下标没有变化,之后的数下标都减了(1),即对于所有(j>i)(B_j)变成了(B_j+1),也就可能存在新的(B_j=0)的情况

    根据上面的事实,那么一开始(B_i>0)的这些值永远也删不掉,且为了删除最多的数,每次肯定选择最右边的(B_i=0)的值进行删除(如果存在下标(i,j)(i<j,B_i=B_j=0),如果先删除(i),那么(j)就删不掉了)

    现在有一个推论:对于某个位置(i),如果(B_i<=0),那么在它之前至少存在(-B_i)个数被删掉,这个数就也可以被删除

    那么对于每个位置(i),满足(B_ile0),存在一个左边界(l),只要第(l)个元素能够删除,那么第(i)个元素也能被删除

    左边界(l)需要满足只考虑([l,i))区间的元素的情况下,可删除元素大于等于(-B_i)个,如果(B_i=0)显然(l=i)

    那么对于每个存在左边界的(i)需要做的就是在(l)的位置加上(1),每个位置的值就表示以这个点为左边界的情况下能删除多少个数,找(l)的方法可以二分之后算区间和或者直接在线段树上二分,前者复杂度(O(log^2n))后者复杂度(O(log n))

    考虑先把询问按右边界从小到大排序(即(y)从大到小排序),遍历每个询问,更新到(i=n-y)的位置,然后计算([x+1,n-y])的区间和就好了

    排序是因为要防止当前不合法的点对左边界产生贡献

    view code
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast,no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define endl "
    "
    #define LL long long int
    #define vi vector<int>
    #define vl vector<LL>
    #define all(V) V.begin(),V.end()
    #define sci(x) scanf("%d",&x)
    #define scl(x) scanf("%lld",&x)
    #define scs(s) scanf("%s",s)
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    #ifndef ONLINE_JUDGE
    #define cout cerr
    #endif
    #define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
    #define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
    #define debug(x)  cerr << #x << " = " << x << endl
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
    template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
    const int MAXN = 3e5+7;
    int n, q, A[MAXN];
    pair<pii,int> Q[MAXN];
    struct SegmentTree{
        int sum[MAXN<<2], l[MAXN<<2], r[MAXN<<2];
        #define ls(rt) rt << 1
        #define rs(rt) rt << 1 | 1
        void build(int L, int R, int rt = 1){
            l[rt] = L; r[rt] = R;
            sum[rt] = 0;
            if(l[rt] + 1 == r[rt]) return;
            int mid = (L + R) >> 1;
            build(L,mid,ls(rt)); build(mid,R,rs(rt));
        }
        void modify(int pos, int x, int rt = 1){
            sum[rt] += x;
            if(l[rt] + 1 == r[rt]) return;
            int mid = (l[rt] + r[rt]) >> 1;
            if(pos<mid) modify(pos,x,ls(rt));
            else modify(pos,x,rs(rt));
        }
        int qsum(int L, int R, int rt = 1){
            if(L>=r[rt] or l[rt]>=R) return 0;
            if(L<=l[rt] and r[rt]<=R) return sum[rt];
            return qsum(L,R,ls(rt)) + qsum(L,R,rs(rt));
        }
        int qpos(int x, int rt = 1){
            if(l[rt] + 1 == r[rt]) return l[rt];
            if(sum[rs(rt)]>=x) return qpos(x,rs(rt));
            else return qpos(x-sum[rs(rt)],ls(rt));
        }
    }ST;
    int ret[MAXN];
    void solve(){
        sci(n); sci(q);
        for(int i = 1; i <= n; i++) sci(A[i]), A[i] -= i;
        for(int i = 1; i <= q; i++){
            sci(Q[i].first.first); sci(Q[i].first.second);
            Q[i].second = i;
        }
        sort(Q+1,Q+1+q,[&](pair<pii,int> &a, pair<pii,int> &b){ return a.first.second > b.first.second; });
        int cur = 1, tot = 0;
        ST.build(0,n+1);
        for(int i = 1; i <= q; i++){
            while(cur<=n-Q[i].first.second){
                if(A[cur]==0) ST.modify(cur,1), tot++;
                else if(A[cur]<0 and -A[cur]<=tot) ST.modify(ST.qpos(-A[cur]),1), tot++;
                cur++;
            }
            ret[Q[i].second] = ST.qsum(Q[i].first.first+1,cur);
        }
        for(int i = 1; i <= q; i++) cout << ret[i] << endl;
    }
    int main(){
        #ifndef ONLINE_JUDGE
        freopen("Local.in","r",stdin);
        freopen("ans.out","w",stdout);
        #endif
        solve();
        return 0;
    }
    
  • 相关阅读:
    JS的中数的取值范围的大小
    前端通过xlsx插件导入excel
    H5和安卓原生进行交互的操作流程记录
    javascript中字符串和数字之间互相转换的方法总结
    gitlab代码合并到主分支
    typeof和valueof、instance of 之间的区别
    javascript中map会改变原始的数组吗
    使用typescript来写react遇到的一些问题
    使用javascript进行时间数据格式的转换
    在vue的移动端项目中使用vue-echarts
  • 原文地址:https://www.cnblogs.com/kikokiko/p/13626353.html
Copyright © 2020-2023  润新知