主席树入门+模板 POJ 2104

来源:互联网 发布:闪电地震流数据 编辑:程序博客网 时间:2024/05/21 01:57

查询区间第K大,而且没有修改。

主席树的原理就是在现有的一颗线段树上不断加入新的节点,而加入的对于现有线段树的影响另开一条链记录下来,这样我们就可以保存线段树的历史版本,在查询时只需要把区间减一下就可以了。

#include <vector>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 1e5+7;vector<int>q;int a[maxn],root[maxn],cnt=0;struct node{int l,r,sum;}T[maxn*20];int getid(int x){return lower_bound(q.begin(),q.end(),x)-q.begin()+1;}void update(int l,int r,int x,int &y,int pos){    T[++cnt]=T[x];T[cnt].sum++;y=cnt; //开辟新的链    if(l==r) return ;    int m = (l+r)>>1;    if(m>=pos) update(l,m,T[x].l,T[y].l,pos);//修改新开辟的链    else update(m+1,r,T[x].r,T[y].r,pos);}int query(int l,int r,int x,int y,int k){    if(l==r) return l;    int m = (l+r)>>1;    int sum = T[T[y].l].sum-T[T[x].l].sum;    if(sum>=k) query(l,m,T[x].l,T[y].l,k);    else query(m+1,r,T[x].r,T[y].r,k-sum);}int main(){    int i,n,m,k,x,y;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++) scanf("%d",a+i),q.push_back(a[i]);    sort(q.begin(),q.end());q.erase(unique(q.begin(),q.end()),q.end());    for(i=1;i<=n;i++)        update(1,n,root[i-1],root[i],getid(a[i]));    for(i=1;i<=m;i++)    {        scanf("%d%d%d",&x,&y,&k);        printf("%d\n",q[query(1,n,root[x-1],root[y],k)-1]);    }    return 0;}


0 0
原创粉丝点击