1 条题解

  • 0
    @ 2025-8-24 22:09:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 枫林晚
    **

    搬运于2025-08-24 22:09:34,当前版本为作者最后更新于2019-04-24 19:49:53,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    %%yyb

    这里说详细一些

    推性质+猜结论

    考虑没有修改。如何快速算出。再数据结构维护修改什么的

    显而易见的是,答案和数列的顺序无关,只和出现的数有关

    如果开一个桶,把每个数摞成若干个柱子,然后往左推倒,那么答案就是[1,n]中未被覆盖的个数。

    证明:

    1.首先这是答案的下界。对于一个空位,比它大的柱子删掉之后不能跨越它,比它小的柱子又不能提前删掉。所以必须变动一个数使得这里被遮盖上。

    2.可以构造出至少一种方案达到这个下界。总数是n,那么有k个空位,就必然有k个重叠的位置。把这些柱子消掉一些,放到空位上,显然没有问题。

    考虑维护

    1.只有p>0,就是单点高度修改了,用个桶就可以O(m)做

    2.还有p=0的整体操作,发现,就是查询区间进行了平移!用一个变量st记录当前0的位置,移动时候直接--st或者++st

    用线段树维护每个点被覆盖的情况

    但是,当一个柱子没有落到[st+1,st+n]的区间上,并且>st+n,这样的柱子并不能贡献覆盖的,一定是之后需要修改的累赘。

    所以,当st--时候,对于原来的最右端的位置,把这个位置的柱子对[p-buc+1,p]的贡献减掉1。++st时候还原

    线段树维护:区间最小值,最小值出现次数,0的个数,加法标记

    这样,查询时候直接区间查询0个数即可

    注意,单点修改的时候,也要判断是否<=st+n

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
    
    namespace Miracle{
    const int N=150000*3+10;
    #define mid ((l+r)>>1)
    #define ls (x<<1)
    #define rs (x<<1|1)
    int n,m;
    struct node{
        int mi,cnt;
        int ans,ad;
    }t[4*N];
    int a[N],buc[N];
    int st,lim;
    void pushup(int x){
        t[x].mi=min(t[ls].mi,t[rs].mi);
        t[x].cnt=(t[ls].mi==t[x].mi?t[ls].cnt:0)+(t[rs].mi==t[x].mi?t[rs].cnt:0);
        t[x].ans=t[ls].ans+t[rs].ans;
    }
    void tag(int x,int c){
        t[x].mi+=c;
        t[x].ans=(t[x].mi==0)?t[x].cnt:0;
        t[x].ad+=c;
    }
    void pushdown(int x){
        if(t[x].ad){
            tag(ls,t[x].ad);tag(rs,t[x].ad);
            t[x].ad=0;
        }
    }
    void build(int x,int l,int r){
        if(l==r){
            t[x].cnt=1;t[x].ans=1;
            return;
        }
        build(ls,l,mid);
        build(rs,mid+1,r);
        pushup(x);
    }
    void upda(int x,int l,int r,int L,int R,int c){
        if(L<=l&&r<=R){
            tag(x,c);return;
        }
        pushdown(x);
        if(L<=mid) upda(ls,l,mid,L,R,c);
        if(mid<R) upda(rs,mid+1,r,L,R,c);
        pushup(x);
    }
    int query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R) return t[x].ans;
        pushdown(x);
        if(R<=mid) return query(ls,l,mid,L,R);
        if(mid<L) return query(rs,mid+1,r,L,R);
        return query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R);
    }
    void chan(int x,int c){
        int k=x-buc[x]+1-(c>0);
        upda(1,1,lim,k,k,c);
        buc[x]+=c;
    }
    int main(){
        rd(n);rd(m);
        st=150000+1,lim=450000+5;//开始0位置和线段树上界
        build(1,1,lim);
        for(reg i=1;i<=n;++i){
            rd(a[i]);a[i]+=st;chan(a[i],1);
        }
        int p,x;
        while(m--){
            rd(p);rd(x);
            if(p>0){//单点修改
                if(a[p]<=st+n){
                    chan(a[p],-1);
                }else{//判断是否<=st+n
                    --buc[a[p]];
                }
                a[p]=st+x;
                if(a[p]<=st+n){
                    chan(a[p],1);
                }else{//判断是否<=st+n
                    ++buc[a[p]];
                }
            }else if(x>0){
                int pos=st+n;
                if(buc[pos]) upda(1,1,lim,pos-buc[pos]+1,pos,-1);//清除贡献
                --st;
            }else{
                ++st;
                int pos=st+n;
                if(buc[pos]) upda(1,1,lim,pos-buc[pos]+1,pos,1);//加上贡献
            }
            printf("%d\n",query(1,1,lim,st+1,st+n));
        }
        return 0;
    }
    
    }
    signed main(){
    	Miracle::main();
    	return 0;
    }
    
    /*
       Author: *Miracle*
    */
    
    
    
    • 1

    信息

    ID
    4306
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者