[BZOJ 3110][Zjoi2013]K大数查询(整体二分+BIT)

Description

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

Solution

标解似乎是树套树?=w=

二分答案。

对于每一个修改,如果c>mid就进行操作,并划到后一个集合里,反之加入前一个集合;对于每一个询问,如果a-b中的数大于c个就划到后一个集合里,反之要减掉a-b中数的个数并加入前一个集合。然后对于两个集合递归下去blahblah

其中数的个数可以用区间修改区间查询的树状数组来维护(树状数组大法好…本来用的是线段树然而打清空标记的操作写得太乱调不下去了)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define MAXN 50005
typedef long long LL;
using namespace std;
int n,m,id[MAXN],t1[MAXN],t2[MAXN],T=0;
LL ans[MAXN];
struct Node1
{
    int opt,a,b;
    LL c;
}O[MAXN];
struct BIT
{
    LL c[MAXN];int sign[MAXN];
    int lowbit(int x){return x&-x;}
    void add(int pos,int x)
    {
        while(pos<=n)
        {
            if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
            c[pos]+=x,pos+=lowbit(pos);
        }
    }
    LL query(int pos)
    {
        LL res=0;
        while(pos>0)
        {
            if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
            res+=c[pos],pos-=lowbit(pos);
        }
        return res;
    }
}c1,c2;
void ADD(int a,int b)
{
    c1.add(a,1),c1.add(b+1,-1);
    c2.add(a,a),c2.add(b+1,-b-1);
}
LL QUERY(int a,int b)
{
    LL res=0;
    res+=(b+1)*c1.query(b)-c2.query(b);
    res-=a*c1.query(a-1)-c2.query(a-1);
    return res;
}
LL read()
{
    LL x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';c=getchar();
    }
    return x*f;
}
void solve(int l,int r,int ansl,int ansr)
{
    if(l>r)return;
    if(ansl==ansr)
    {
        for(int i=l;i<=r;i++)
        if(O[id[i]].opt==2)ans[id[i]]=ansl;
        return;
    }
    int mid=(ansl+ansr)>>1;
    int j=1,k=1;
    T++;
    for(int i=l;i<=r;i++)
    {
        int idx=id[i];
        if(O[idx].opt==1)
        {
            if(O[idx].c<=mid)t1[j++]=idx;
            else t2[k++]=idx,ADD(O[idx].a,O[idx].b);
        }
        else
        {
            LL res=QUERY(O[idx].a,O[idx].b);
            if(res>=O[idx].c)t2[k++]=idx;
            else t1[j++]=idx,O[idx].c-=res;
        }
    }
    --j,--k;
    for(int i=1;i<=j;i++)id[l+i-1]=t1[i];
    for(int i=1;i<=k;i++)id[l+j+i-1]=t2[i];
    solve(l,l+j-1,ansl,mid),solve(l+j,r,mid+1,ansr);
    
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    O[i].opt=read(),O[i].a=read(),O[i].b=read(),O[i].c=read(),id[i]=i;
    solve(1,m,-n,n);
    for(int i=1;i<=m;i++)
    if(O[i].opt==2)printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2017-05-24 20:48  Zars19  阅读(305)  评论(0编辑  收藏  举报