bzoj3110 [Zjoi2013]K大数查询

题目描述

题解:

看不懂样例的dalao看这里:

每个位置加入一个数c指的是插入,一个位置上可以有很多数

整体二分。

将修改和询问放在一起,然后二分值域,每次有询问时判断$k$和$sum[l,r]$的大小。

最后保证$[l,l]$时$k$减成$0$即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50050
#define ll long long
inline ll rd()
{
    ll f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    return f*c;
}
ll n,m,cnt;
ll ans[N],to[N];
struct str
{
    ll opt,a,b,id;
    ll c;
}p[N],tmpl[N],tmpr[N];
ll tot;
struct Pair
{
    ll x;ll id;
    Pair(){}
    Pair(ll x,ll i):x(x),id(i){}
}pr[N];
bool cmp(Pair a,Pair b)
{
    return a.x<b.x;
}
struct segtree
{
    ll siz[N<<2],vl[N<<2],tag[N<<2];
    bool rec[N<<2];
    void add(ll u,ll d)
    {
        tag[u]+=d;
        vl[u]+=siz[u]*d;
    }
    void rece(ll u)
    {
        rec[u]=1;
        vl[u]=tag[u]=0;
    }
    void update(ll u)
    {
        vl[u] = vl[u<<1]+vl[u<<1|1];
    }
    void build(ll l,ll r,ll u)
    {
        siz[u] = r-l+1;
        if(l==r)return ;
        ll mid = (l+r)>>1;
        build(l,mid,u<<1);
        build(mid+1,r,u<<1|1);
    }
    void init()
    {
        build(1,n,1);
    }
    void pushdown(ll u)
    {
        if(rec[u])
        {
            rece(u<<1);
            rece(u<<1|1);
            rec[u]=0;
        }
        if(tag[u])
        {
            add(u<<1,tag[u]);
            add(u<<1|1,tag[u]);
            tag[u]=0;
        }
    }
    void insert(ll l,ll r,ll u,ll ql,ll qr,ll d)
    {
        if(l==ql&&r==qr)
        {
            add(u,d);
            return ;
        }
        pushdown(u);
        ll mid = (l+r)>>1;
        if(qr<=mid)insert(l,mid,u<<1,ql,qr,d);
        else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,d);
        else insert(l,mid,u<<1,ql,mid,d),insert(mid+1,r,u<<1|1,mid+1,qr,d);
        update(u);
    }
    ll query(ll l,ll r,ll u,ll ql,ll qr)
    {
        if(l==ql&&r==qr)return vl[u];
        pushdown(u);
        ll mid = (l+r)>>1;
        if(qr<=mid)return query(l,mid,u<<1,ql,qr);
        else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr);
        else return query(l,mid,u<<1,ql,mid)+query(mid+1,r,u<<1|1,mid+1,qr);
    }
}tr;
void divi(ll l,ll r,ll beg,ll ens)
{
    if(beg>ens)return ;
    if(l==r)
    {
        for(ll i=beg;i<=ens;i++)
            ans[p[i].id] = to[l];
        return ;
    }
    ll mid = (l+r)>>1;
    ll lt = 0,rt = 0;
    tr.rece(1);
    bool l1=0,r1=0;
    for(ll i=beg;i<=ens;i++)
    {
        if(p[i].opt==1)
        {
            if(p[i].c<=mid)
            {
                tmpl[++lt] = p[i];
            }else
            {
                tr.insert(1,n,1,p[i].a,p[i].b,1);
                tmpr[++rt] = p[i];
            }
        }else
        {
            ll now = tr.query(1,n,1,p[i].a,p[i].b);
            if(now<p[i].c)
            {
                p[i].c-=now;
                tmpl[++lt] = p[i];
                l1=1;
            }else
            {
                tmpr[++rt] = p[i];
                r1=1;
            }
        }
    }
    for(ll i=beg;i<=beg+lt-1;i++)p[i]=tmpl[i-beg+1];
    for(ll i=beg+lt;i<=ens;i++)p[i]=tmpr[i-beg-lt+1];
    if(l1)divi(l,mid,beg,beg+lt-1);
    if(r1)divi(mid+1,r,beg+lt,ens);
}
int main()
{
//    freopen("tt.in","r",stdin);
//    freopen("tt.out","w",stdout);
    n = rd(),m = rd();
    for(ll i=1;i<=m;i++)
    {
        p[i].opt = rd(),p[i].a = rd(),p[i].b = rd(),p[i].c = rd();
        if(p[i].opt==2)
        {
            p[i].id = ++cnt;
        }else
        {
            pr[++tot] = Pair(p[i].c,i);
        }
    }
    sort(pr+1,pr+1+tot,cmp);
    ll las = 100005;ll k = 0;
    for(ll i=1;i<=tot;i++)
    {
        if(las!=pr[i].x)
        {
            las = pr[i].x;
            k++;to[k]=las;
        }
        p[pr[i].id].c = k;
    }
    tr.init();
    divi(1,k,1,m);
    for(ll i=1;i<=cnt;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

 

posted @ 2018-12-31 09:40  LiGuanlin  阅读(125)  评论(0编辑  收藏  举报