【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;
}


posted @ 2017-11-28 16:29  一剑霜寒十四洲  阅读(201)  评论(0编辑  收藏  举报