zoukankan      html  css  js  c++  java
  • 【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
    ",Hash[query(1,1,50000,a[i].c)]);
    	}
    	return 0;
    }


  • 相关阅读:
    试用第三方web推送GoEasy
    使用intellj idea 搭建本地开发环境
    一种基于struts2 拦截器 和 log4j的轻量级crm权限及行为跟踪方式
    Spring AOP声明式事务异常回滚 若干法则
    spring aop 切面测试
    centos 安装 mysql
    只是 换个方式,
    contrller 是 file's owners,
    色差,15,还是15 ,换了颜色 就显的小了,
    一块,分开,还是不分开 一个整体,
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476915.html
Copyright © 2011-2022 走看看