BZOJ-3110: [Zjoi2013]K大数查询

[文章目录]

Description

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。N,M<=50000,abs(c)<=N

权值线段树套线段树维护区间的个数。
外层维护权值,内层维护外层该权值区间下的所有权值在每个区间的个数。
对于一个修改,我们在外层含有c的区间的内层区间[a,b]+1
对于询问,我们在外层二分,内层查询在该区间的权值个数。
时间复杂度

#include <cstdio>
#include <cstring>
#include <algorithm>
#define U unsigned 
using namespace std;
struct seg
{
    int ls,rs;
    U int lz,siz;
}t[30000000];
int tot;
inline void pushup(int pos)
{
    t[pos].siz=t[t[pos].ls].siz+t[t[pos].rs].siz;
}
inline void pushdown(int pos,int l,int r)
{
    if(t[pos].lz)
    {
        int mid=(l+r)>>1,ls,rs;
        if(!t[pos].ls) t[pos].ls=++tot;
        if(!t[pos].rs) t[pos].rs=++tot;
        ls=t[pos].ls; rs=t[pos].rs;
        t[ls].siz+=t[pos].lz*(mid-l+1);
        t[rs].siz+=t[pos].lz*(r-mid);
        t[ls].lz+=t[pos].lz;
        t[rs].lz+=t[pos].lz;
        t[pos].lz=0;
    }
}
void fix(int &pos,int l,int r,int x,int y)
{
    if(!pos) pos=++tot;
    if(x<=l&&y>=r)
    {
        t[pos].siz+=r-l+1;
        t[pos].lz++; return ;
    }
    int mid=(l+r)>>1; pushdown(pos,l,r);
    if(y<=mid) fix(t[pos].ls,l,mid,x,y);
    else if(x>mid) fix(t[pos].rs,mid+1,r,x,y);
    else fix(t[pos].ls,l,mid,x,y),fix(t[pos].rs,mid+1,r,x,y);
    pushup(pos);
}
U int query(int pos,int l,int r,int x,int y)
{
    if(!pos) return 0;
    if(x<=l&&y>=r) return t[pos].siz;
    int mid=(l+r)>>1; pushdown(pos,l,r);
    if(y<=mid) return query(t[pos].ls,l,mid,x,y);
    else if(x>mid) return query(t[pos].rs,mid+1,r,x,y);
    else return query(t[pos].ls,l,mid,x,y)+query(t[pos].rs,mid+1,r,x,y);
}
int n,m;
int rt[401000];
int main()
{
    scanf("%d%d",&n,&m);
    U int tmp; int sw,a,b,c,L,R,Mid,P;
    while(m--)
    {
        scanf("%d%d%d%d",&sw,&a,&b,&c);
        if(sw&1)
        {
            c+=n; L=0,R=n<<1,P=1;
            while(L<R)
            {
                fix(rt[P],1,n,a,b);
                Mid=(L+R)>>1;
                if(c<=Mid) R=Mid,P=P<<1;
                else L=Mid+1,P=P<<1|1;
            }
            fix(rt[P],1,n,a,b);
        }
        else
        {
            L=0,R=n<<1,P=1;
            while(L<R)
            {
                Mid=(L+R)>>1;
                tmp=query(rt[P<<1|1],1,n,a,b);
                if((U int)c<=tmp) P=P<<1|1,L=Mid+1;
                else c-=tmp,P=P<<1,R=Mid;
            }
            printf("%d\n",L-n);
        }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注