bzoj3110 zjoi2013 K大数查询

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


正解:整体二分

一道整体二分板子题。。这回竟然调线段树调了好久。。

先以时间为序,二分答案,大于mid的修改就更新,对于每个询问,如果这段区间大于mid的数>=k,说明当前答案小了,放到右半区间,否则放到左半区间。

//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define ls (x<<1)
#define rs (x<<1|1)
#define il inline
#define RG register
#define uint long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)

using namespace std;

struct node{ uint t,l,r,k,id; }q[50010],qu1[50010],qu2[50010];

uint sum[500010],lazy[500010],ans[50010],n,m,cnt;

il uint gi(){
    RG uint x=0,q=0; RG char ch=getchar();
    while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=1,ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
}

il void down(RG uint x,RG uint l,RG uint r){
    RG uint mid=(l+r)>>1;
    sum[ls]+=(mid-l+1)*lazy[x],sum[rs]+=(r-mid)*lazy[x];
    lazy[ls]+=lazy[x],lazy[rs]+=lazy[x],lazy[x]=0;
    return;
}

il void update(RG uint x,RG uint l,RG uint r,RG uint xl,RG uint xr,RG uint v){
    if (xl<=l && r<=xr){ sum[x]+=(r-l+1)*v,lazy[x]+=v; return; }
    if (lazy[x]) down(x,l,r); RG uint mid=(l+r)>>1;
    if (xr<=mid) update(ls,l,mid,xl,xr,v);
    else if (xl>mid) update(rs,mid+1,r,xl,xr,v);
    else update(ls,l,mid,xl,mid,v),update(rs,mid+1,r,mid+1,xr,v);
    sum[x]=sum[ls]+sum[rs]; return;
}

il uint query(RG uint x,RG uint l,RG uint r,RG uint xl,RG uint xr){
    if (xl<=l && r<=xr) return sum[x];
    if (lazy[x]) down(x,l,r); RG uint mid=(l+r)>>1,res=0;
    if (xr<=mid) res=query(ls,l,mid,xl,xr);
    else if (xl>mid) res=query(rs,mid+1,r,xl,xr);
    else res=query(ls,l,mid,xl,mid)+query(rs,mid+1,r,mid+1,xr);
    return res;
}

il void solve(RG uint l,RG uint r,RG uint L,RG uint R){
    if (l>r) return; if (L==R){ for (RG uint i=l;i<=r;++i) if (q[i].t==2) ans[q[i].id]=L; return; }
    RG uint mid=(L+R)>>1,t1=0,t2=0;
    for (RG uint i=l;i<=r;++i)
	if (q[i].t==1){ if (q[i].k>mid) update(1,1,n,q[i].l,q[i].r,1),qu2[++t2]=q[i]; else qu1[++t1]=q[i]; }
	else{
	    RG uint res=query(1,1,n,q[i].l,q[i].r);
	    if (res>=q[i].k) qu2[++t2]=q[i]; else q[i].k-=res,qu1[++t1]=q[i]; }
    for (RG uint i=l;i<=r;++i) if (q[i].t==1 && q[i].k>mid) update(1,1,n,q[i].l,q[i].r,-1);
    for (RG uint i=l,j=1;j<=t1;++i,++j) q[i]=qu1[j]; for (RG uint i=l+t1,j=1;j<=t2;++i,++j) q[i]=qu2[j];
    solve(l,l+t1-1,L,mid),solve(l+t1,r,mid+1,R); return;
}

il void work(){
    n=gi(),m=gi();for (RG uint i=1;i<=m;++i){ q[i].t=gi(),q[i].l=gi(),q[i].r=gi(),q[i].k=gi();if (q[i].t==2) q[i].id=++cnt; }
    solve(1,m,1,n); for (RG uint i=1;i<=cnt;++i) printf("%lld\n",ans[i]); return;
}

int main(){
    File("bzoj3110");
    work();
    return 0;
}



posted @ 2017-01-20 10:07  wfj_2048  阅读(132)  评论(0编辑  收藏  举报