[poj 2104]主席树+静态区间第k大

题目链接:http://poj.org/problem?id=2104

主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即可得到第k大(小)元素。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

#define lson(i) node[i].lson
#define rson(i) node[i].rson

const int maxn=100005;
int rt[maxn];

struct Node
{
    int lson,rson,val;
}node[maxn*30];
int tot;

void push_up(int i)
{
    node[i].val=node[lson(i)].val+node[rson(i)].val;
}

int build(int l,int r)
{
    int i=++tot;
    if (l==r) node[i].val=0;
    else
    {
        int mid=(l+r)/2;
        lson(i)=build(l,mid);
        rson(i)=build(mid+1,r);
        push_up(i);
    }
    return i;
}

int rebuild(int k,int x,int i,int nowl,int nowr)
{
    int th=++tot;
    lson(th)=lson(i);
    rson(th)=rson(i);
    node[th].val=node[i].val;
    if (nowl==nowr) node[th].val+=x;
    else
    {
        int mid=(nowl+nowr)/2;
        if (k<=mid) node[th].lson=rebuild(k,x,lson(i),nowl,mid);
        else node[th].rson=rebuild(k,x,rson(i),mid+1,nowr);
        push_up(th);
    }
    return th;
}

int query(int rt1,int rt2,int k,int nowl,int nowr)
{
    if (nowl==nowr) return nowl;
    int left=node[lson(rt2)].val-node[lson(rt1)].val;
    int mid=(nowl+nowr)/2;
    if (left>=k) return query(lson(rt1),lson(rt2),k,nowl,mid);
    else return query(rson(rt1),rson(rt2),k-left,mid+1,nowr);
}

int a[maxn];
vector<int> ls;

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    ls.clear();
    for (int i=1;i<=n;i++) ls.push_back(a[i]);
    sort(ls.begin(),ls.end());
    ls.erase(unique(ls.begin(),ls.end()),ls.end());
    rt[0]=build(1,n);
    for (int i=1;i<=n;i++)
    {
        int j=lower_bound(ls.begin(),ls.end(),a[i])-ls.begin();
        rt[i]=rebuild(j+1,1,rt[i-1],1,n);
    }
    for (int i=1;i<=m;i++)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",ls[query(rt[l-1],rt[r],k,1,n)-1]);
    }
    return 0;
}

 

posted @ 2017-08-16 15:54  ACMsong  阅读(163)  评论(0编辑  收藏  举报