k-th number(主席树 )

来源:互联网 发布:java if else嵌套 编辑:程序博客网 时间:2024/05/01 09:30

题意:给一堆数,找区间第k大的数。

主席树是指在一棵树的基础上复制一棵树,同时又在其中加入一个点。
可以用来查询第k大的点。
这个与直接建立多颗线段树还是有区别的。
这个复制可以节省很多内存~

代码如下:

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;const int maxn=100010;/*线段树点记录的是数字出现的次数*/struct node{    int L,R,sum;       }tree[maxn*20];struct node1{    int x,id;           bool operator <(node1 y)const{//重载运算符,<时以x的大小来判断。sort时用到        return x<y.x;    }}a[maxn];int cnt,n,m;int root[maxn],rank[maxn];void create_tree(int num,int &x,int l,int r){//num表示离散化后的编号,x表示根节点,l,r不解释    tree[cnt++]=tree[x],x=cnt-1;//结构体复制,将新建的树复制成上一棵树     /*在树上新增一个节点*/    ++tree[x].sum;    if(l==r) return;    int mid=(l+r)>>1;    /*建树的点的位置*/    if(num<=mid) create_tree(num,tree[x].L,l,mid);//左边则向左子树找     else create_tree(num,tree[x].R,mid+1,r);//右边则向右子树 }int query(int i,int j,int z,int l,int r){    if(l==r) return l;    int t=tree[tree[j].L].sum-tree[tree[i].L].sum;    //先搜索左子树,如果规定区间内的个数比要求的个数多,则在左子树内,反之成立    int mid=(l+r)>>1;    if(z<=t) return query(tree[i].L,tree[j].L,z,l,mid);    else return query(tree[i].R,tree[j].R,z-t,mid+1,r);}int main(){    int i,j;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++){        scanf("%d",&a[i].x);         a[i].id=i;    }    sort(a+1,a+1+n);    for(i=1;i<=n;i++) rank[a[i].id]=i;//离散化    cnt=1;    //for(i=1;i<=n;i++) printf("%d ",rank[i]);    for(i=1;i<=n;i++){        root[i]=root[i-1];//将根节点复制        create_tree(rank[i],root[i],1,n);//建树     }    for(i=1;i<=m;i++){        int p,q,z;        scanf("%d%d%d",&p,&q,&z);        printf("%d\n",a[query(root[p-1],root[q],z,1,n)].x); //用根节点来表示树                    }    return 0;    }
1 0
原创粉丝点击