bzoj3110

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 5881  Solved: 1958
[Submit][Status][Discuss]

Description

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

Input

第一行N,M
接下来M行,每行形如1 a b c或2 a b c

Output

输出每个询问的结果

Sample Input

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

Sample Output

1
2
1

HINT



【样例说明】

第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1

的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是

1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3

大的数是 1 。‍

 

N,M<=50000,N,M<=50000

a<=b<=N

1操作中abs(c)<=N

2操作中c<=Maxlongint

整体二分是什么东西? 我们知道 主席树查询是一个类似二分的过程,但是这道题有修改,一次一次修改太慢了,这时就用上二分的思想了。

一个一个二分太慢了,那么我们把一堆东西一起二分,也就是把他们不断地划分,归类。

二分一个lb和ub,比(lb+ub)/2大的归到右边,小的归到左边,然后就完了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500010
typedef long long ll;
struct data
{
    ll v;
    ll l,r,type,pos;
}op[N];
vector<data> lp,rp;
ll n,m;
ll tag[N*6],t[N*6],ans[N];
bool flag[N*6];
void update(int l,int r,int x,int a,int b,int num)
{
    if(l>b||r<a) return;
    if(l>=a&&r<=b) 
    {
        tag[x]+=num;
        return;
    }
    t[x]+=(min(r,b)-max(l,a)+1)*num;
    update(l,(l+r)/2,x*2,a,b,num);
    update((l+r)/2+1,r,x*2+1,a,b,num);
}
ll query(int l,int r,int x,int a,int b)
{
    if(l>b||r<a) return 0;
    if(l>=a&&r<=b) return t[x]+(r-l+1)*tag[x];
    ll ret=0;
    ret+=(min(r,b)-max(l,a)+1)*tag[x];
    ret+=query(l,(l+r)/2,x*2,a,b);
    ret+=query((l+r)/2+1,r,x*2+1,a,b);
    return ret;
}
void solve(int l,int r,int lb,int ub)
{
//    printf("((((((((((((((((((((((\n");
//    printf("lb=%d ub=%d\n",lb,ub);
//    printf("left=%d right=%d\n",l,r);
    if (l > r) return ;
    if(lb==ub)
    {
        for(int i=l;i<=r;i++)
            if(op[i].type==2)
            {
                flag[op[i].pos]=true;
                ans[op[i].pos]=lb;
            }
        return;
    }
    ll mb=lb+(ub-lb)/2;
    lp.clear(); rp.clear();
    for(int i=l;i<=r;i++)
    {
        if(op[i].type==1)
        {
            if(op[i].v>mb) 
            {
//                printf("------------\n");
//                printf("l=%d r=%d\n",op[i].l,op[i].r);
                update(1,n,1,op[i].l,op[i].r,1);
//                printf("------------\n");
                rp.push_back(op[i]);
            }
            else 
                lp.push_back(op[i]);
        } 
        else
        {
            ll c=query(1,n,1,op[i].l,op[i].r);
//            printf("op[i].l=%d op[i].r=%d\n",op[i].l,op[i].r);
//            printf("c=%d\n",c);
            if(c>=op[i].v)
            {
                rp.push_back(op[i]);
            }
            else
            {
                op[i].v-=c;
                lp.push_back(op[i]);
            }
        }
    }
    
    for(int i=l;i<=r;i++)
    {
        if(op[i].type==1&&op[i].v>mb) 
          update(1,n,1,op[i].l,op[i].r,-1);
    }
    
    ll mid=l+lp.size();
    for(int i=0;i<lp.size();i++)
    {
        op[i+l]=lp[i];
    }
    for(int i=0;i<rp.size();i++)
    {
        op[mid+i]=rp[i];
    }
//    printf(")))))))))))))))))))))\n");
    solve(l,mid-1,lb,mb);
    solve(mid,r,mb+1,ub);
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld%lld",&op[i].type,&op[i].l,&op[i].r,&op[i].v);        
        op[i].pos=i;
    }
    solve(1,m,-n,n);
    for(int i=1;i<=m;i++)
    {
        if(flag[i]) printf("%lld\n",ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2016-12-18 01:46  19992147  阅读(335)  评论(0编辑  收藏  举报