ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】Luogu P5324 [BJOI2019]删数

2019-05-21 21:51:54  阅读:282  来源: 互联网

标签:BJOI2019 p2 ch int 题解 删数 p1 buf getchar


原题传送门

易知这个数列的顺序是不用考虑的

我们看两个数列 \(1,2,3\)和\(3,3,3\)都能删完,再看两个数列\(1,2,3,4\)和\(2,2,4,4\)

不难发现,我们珂以把这些数字塞进桶中,记\(cnt_i\)表示数字\(i\)出现的次数,对于每个\(i\),在一颗线段树上把区间\([i-cnt_i+1,i]\)赋值成1(因为一次删\(cnt_i\)个珂以转化成每次删\(1\)个,从大向小递减),最后看[1,n]上有几个点不是1,这就是题目所求的答案

单点修改就直接在线段树上单点修改,区间加减实际就相当于线段树值域平移,但这个实在太麻烦,相对的,我们珂以平移查询区间

时间复杂度是\(O(m\log (2m+n))\)

假·完整代码(这个是假算法)

#include <bits/stdc++.h>
#define N 450005 
#define M 150005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
int n,m,a[M],lim,cnt[N],w;
int tr[N<<3],sum[N];
inline void modify(register int x,register int l,register int r,register int pos,register int val)
{
    if(l==r)
    {
        tr[x]=val;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        modify(x<<1,l,mid,pos,val);
    else
        modify(x<<1|1,mid+1,r,pos,val);
    tr[x]=tr[x<<1]+tr[x<<1|1];
}
inline int query(register int x,register int l,register int r,register int L,register int R)
{
    if(L<=l&&r<=R)
        return tr[x];
    int mid=l+r>>1,res=0;
    if(L<=mid)
        res+=query(x<<1,l,mid,L,R);
    if(R>mid)
        res+=query(x<<1|1,mid+1,r,L,R);
    return res;
}
int main()
{
    n=read(),m=read();
    lim=m+n*2;
    memset(cnt,0,sizeof(cnt));
    memset(sum,0,sizeof(sum));
    for(register int i=1;i<=n;++i)
    {
        a[i]=read();
        if((++sum[n+a[i]-cnt[a[i]+m]])==1)
            modify(1,1,lim,n+a[i]-cnt[a[i]+m],1);
        ++cnt[a[i]+m];
    }
    for(register int i=1;i<=m;++i)
    {
        int opt=read(),x=read();
        if(opt)
        {
            x-=w;
            --cnt[a[opt]+m];
            if((--sum[n+a[opt]-cnt[a[opt]+m]])==0)
                modify(1,1,lim,n+a[opt]-cnt[a[opt]+m],0);
            a[opt]=x;
            if((++sum[n+a[opt]-cnt[a[opt]+m]])==1)
                modify(1,1,lim,n+a[opt]-cnt[a[opt]+m],1);
            ++cnt[a[opt]+m];
        }
        else
            w+=x;
        write(n-query(1,1,lim,n+1-w,n+n-w)),puts("");
    }
    return 0;
}

交一发,发现会WA46

实际因为我们有种情况没有考虑:当\(val>n\)时,所有的都要修改,然而到线段树上就变成了一段区间,会对答案造成影响

我们只需要特判一些就珂以了

真·完整代码

#include <bits/stdc++.h>
#define N 450005 
#define M 150005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline int Max(register int a,register int b)
{
    return a>b?a:b;
}
int n,m,a[M],b[N],cnt[N],c,ql,qr,lim;
int pm[N<<3],len[N<<3],tag[N<<3];
inline void pushup(register int x)
{
    int ls=x<<1,rs=x<<1|1;
    pm[x]=pm[ls],len[x]=len[ls];
    if(pm[rs]<pm[x])
        pm[x]=pm[rs],len[x]=len[rs];
    else if(pm[rs]==pm[x])
        len[x]+=len[rs];
}
inline void build(register int x,register int l,register int r)
{
    if(l==r)
    {
        pm[x]=b[l];
        len[x]=1;
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
inline void pushdown(register int x)
{
    if(tag[x])
    {
        int ls=x<<1,rs=x<<1|1;
        tag[ls]+=tag[x],tag[rs]+=tag[x];
        pm[ls]+=tag[x],pm[rs]+=tag[x];
        tag[x]=0;
    }
}
inline void modify(register int x,register int l,register int r,register int L,register int R,register int val)
{
    if(L<=l&&r<=R)
    {
        pm[x]+=val;
        tag[x]+=val;
        return;
    }
    int mid=l+r>>1;
    pushdown(x);
    if(L<=mid)
        modify(x<<1,l,mid,L,R,val);
    if(R>mid)
        modify(x<<1|1,mid+1,r,L,R,val);
    pushup(x);
}
inline int query(register int x,register int l,register int r,register int L,register int R)
{
    if(L<=l&&r<=R)
        return pm[x]?0:len[x];
    int mid=l+r>>1,res=0;
    pushdown(x);
    if(L<=mid)
        res+=query(x<<1,l,mid,L,R);
    if(R>mid)
        res+=query(x<<1|1,mid+1,r,L,R);
    return res;
}
int main()
{
    n=read(),m=read();
    c=Max(n,m);
    for(register int i=1;i<=n;++i)
    {
        a[i]=read();
        ++cnt[a[i]+=c];
    }
    ql=c+1,qr=c+n,lim=c*2+n;
    for(register int i=m+1;i<=qr;++i)
        ++b[i-cnt[i]+1],--b[i+1];
    for(register int i=2;i<=qr+1;++i)
        b[i]+=b[i-1];
    build(1,1,lim);
    for(register int i=1;i<=m;++i)
    {
        int opt=read(),x=read();
        if(opt)
        {
            --cnt[a[opt]];
            if(a[opt]<=qr)
                modify(1,1,lim,a[opt]-cnt[a[opt]],a[opt]-cnt[a[opt]],-1);
            a[opt]=x+ql-1;
            modify(1,1,lim,a[opt]-cnt[a[opt]],a[opt]-cnt[a[opt]],1);
            ++cnt[a[opt]];
        }
        else
        {
            if(x==1)
            {
                if(cnt[qr])
                    modify(1,1,lim,qr-cnt[qr]+1,qr,-1);
                --ql,--qr;
            }
            else
            {
                ++ql,++qr;
                if(cnt[qr])
                    modify(1,1,lim,qr-cnt[qr]+1,qr,1);
            }
        }
        write(query(1,1,lim,ql,qr)),puts("");
    }
    return 0;
}

标签:BJOI2019,p2,ch,int,题解,删数,p1,buf,getchar
来源: https://www.cnblogs.com/yzhang-rp-inf/p/10902621.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有