• POJ_2104_K-th Number_主席树


    POJ_2104_K-th Number_主席树

    题意:给定一个长度为n的序列,m次询问区间第k小

    分析:

    主席树模板

    主席树可以理解成为n棵权值线段树的前缀和

    但我们不能建n棵线段树,只需要对于每个修改的结点新建一个点,剩下的儿子什么的连到上一棵树的儿子上

    这样做到节约空间,实际上我们只需要开nlogn的空间

    对于这道题就相当于对每个前缀建一棵树

    查询的时候前缀和相减,在相减后的线段树上查询

    代码简短思路清晰

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    int t[N*20],n,m,a[N],root[N],tot,ls[N*20],rs[N*20];
    struct A
    {
    	int num,id,v;
    }d[N];
    bool cmp1(const A &x,const A &y)
    {
    	return x.num<y.num;
    }
    bool cmp2(const A &x,const A &y)
    {
    	return x.id<y.id;
    }
    void insert(int x,int &y,int l,int r,int val)
    {
    	y=++tot;
    	if(l==r){ t[y] = t[x] + 1; return ; }
    	int mid=l+r>>1;
    	if(val<=mid) rs[y]=rs[x],insert(ls[x],ls[y],l,mid,val);
    	else ls[y]=ls[x],insert(rs[x],rs[y],mid+1,r,val);
    	t[y]=t[ls[y]]+t[rs[y]];
    }
    int query(int x,int y,int l,int r,int k)
    {
    	if(l==r)return a[l];
    	int sizls=t[ls[y]]-t[ls[x]],mid=l+r>>1;
    	if(k<=sizls) return query(ls[x],ls[y],l,mid,k);
    	else return query(rs[x],rs[y],mid+1,r,k-sizls); 
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i,x,y,k,j;
    	for(i=1;i<=n;i++) scanf("%d",&d[i].num),d[i].id=i;
    	sort(d+1,d+n+1,cmp1);d[0].num=453753322;
    	for(i=1,j=0;i<=n;i++) { if(d[i].num!=d[i-1].num)j++;d[i].v=j;a[j]=d[i].num; }
    	sort(d+1,d+n+1,cmp2);
    	for(i=1;i<=n;i++) insert(root[i-1],root[i],1,n,d[i].v);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&k);
    		printf("%d
    ",query(root[x-1],root[y],1,n,k));
    	}
    }
    
  • 相关阅读:
    洛谷 1736 创意吃鱼法
    有多重限制的背包
    洛谷 1417 烹调方案
    2008 noip 传纸条
    环形石子合并 洛谷 1880 && hdu 3506 Monkey Party
    洛谷 1282 多米诺骨牌
    (金明的预算方案)依赖性的背包
    分组背包问题
    混合背包问题
    多重背包问题
  • 原文地址:https://www.cnblogs.com/suika/p/8593455.html
Copyright © 2020-2023  润新知