【BZOJ3110】K大数查询【树套树 线段树套线段树】
【BZOJ3110】K大数查询
Description
有N个位置,M个操作。操作有两种,每次操作
如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。
如果是2 a b 的c形式,表示询问从第a个位置到第b个位置,第c大的数是多少。Input
第一行两个数N,M。接下来M行,每行形如
Output
输出每个询问的结果
题解:树套树。外层建一棵权值线段树,每一个节点又是一棵线段树,这棵线段树储存内层每个节点所对应的区间的每个数出现的次数。查询的时候,在外层的线段树上二分权值,求出目前对应的权值区间的右侧(mid+1到r那一段)在查询的位置区间内有多少个数。如果个数比当前查询的排名大就往权值线段树左侧走,否则往右侧走。当(l==r)时,就找到了对应的权值。修改时,就在线段树上走一遍,更新出现的次数。注意,为了省空间和时间,要离散化!此处我用的是李超线段树,没有pushdown操作。李超线段树常数真小,跑得真快!坑的是,答案会爆int!因为这一点wa了一整个下午。
最后是并不长的代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,now,rt,cnt=0,root[200005],tag[15000005],lc[15000005],rc[15000005];
unsigned int sumv[15000005];
int Hash[50005];
struct operation{
int op,a,b,c;
}a[50005];
int getid(int a){
return lower_bound(Hash+1,Hash+Hash[0]+1,a)-Hash;
}
void upd(int &o,int l,int r,int L,int R){
if(!o) o=++cnt;
sumv[o]+=R-L+1;
if(L==l&&R==r)
{
tag[o]++;
return;
}
int mid=(l+r)/2;
if(R<=mid) upd(lc[o],l,mid,L,R);
else if(L>mid) upd(rc[o],mid+1,r,L,R);
else
{
upd(lc[o],l,mid,L,mid);
upd(rc[o],mid+1,r,mid+1,R);
}
}
void update(int o,int l,int r,int k){
upd(root[o],1,n,a[now].a,a[now].b);
if(l==r) return;
int mid=(l+r)/2;
if(k<=mid) update(o*2,l,mid,k);
else update(o*2+1,mid+1,r,k);
}
unsigned int qry(int o,int l,int r,int L,int R){
if(!o) return 0;
if(L==l&&R==r) return sumv[o];
int mid=(l+r)/2;
unsigned int ans=tag[o]*(R-L+1);
if(R<=mid) ans+=qry(lc[o],l,mid,L,R);
else if(L>mid) ans+=qry(rc[o],mid+1,r,L,R);
else ans+=qry(lc[o],l,mid,L,mid)+qry(rc[o],mid+1,r,mid+1,R);
return ans;
}
int query(int o,int l,int r,int k){
if(l==r) return l;
int mid=(l+r)/2;
unsigned int siz=qry(root[o*2+1],1,n,a[now].a,a[now].b);
if(k>siz) return query(o*2,l,mid,k-siz);
else return query(o*2+1,mid+1,r,k);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&a[i].op,&a[i].a,&a[i].b,&a[i].c);
if(a[i].op==1) Hash[++Hash[0]]=a[i].c;
}
sort(Hash+1,Hash+Hash[0]+1);
Hash[0]=unique(Hash+1,Hash+Hash[0]+1)-Hash-1;
for(int i=1;i<=m;i++){
now=i;
if(a[i].op==1) update(1,1,50000,getid(a[i].c));
else printf("%d\n",Hash[query(1,1,50000,a[i].c)]);
}
return 0;
}