区间第K大(划分树)

来源:互联网 发布:monaco windows 编辑:程序博客网 时间:2024/05/01 06:53

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1175

 

注意一个很明显的结论:求区间[p,q]的第K大就等于求区间[p,q]的第q-p+1-k小。

#include <iostream>#include <string.h>#include <algorithm>#include <stdio.h>using namespace std;const int N = 100005;int sorted[N];int Tree[20][N];int toLeft[20][N];void Build(int k,int l,int r){    if(l==r) return;    int mid=(l+r)>>1;    int i,t;    t=mid-l+1;    for(i=l;i<=r;i++)       if(Tree[k][i]<sorted[mid])          t--;    int L=l;    int R=mid+1;    for(i=l;i<=r;i++)    {       if(i==l)          toLeft[k][i]=0;       else          toLeft[k][i]=toLeft[k][i-1];       if(Tree[k][i]<sorted[mid])       {           toLeft[k][i]++;           Tree[k+1][L++]=Tree[k][i];       }       else if(Tree[k][i]>sorted[mid])       {           Tree[k+1][R++]=Tree[k][i];       }       else       {           if(t!=0)           {               t--;               toLeft[k][i]++;               Tree[k+1][L++]=Tree[k][i];           }           else               Tree[k+1][R++]=Tree[k][i];       }    }    Build(k+1,l,mid);    Build(k+1,mid+1,r);}int Query(int k,int l,int r,int p,int q,int t){    if(p==q) return Tree[k][p];    int s,ss;    int mid=(l+r)>>1;    if(l==p)    {        s=0;        ss=toLeft[k][q];    }    else    {        s=toLeft[k][p-1];        ss=toLeft[k][q]-s;    }    int L,R;    if(t<=ss)    {        L=l+s;        R=l+s+ss-1;        return Query(k+1,l,mid,L,R,t);    }    else    {        L=mid-l+1+p-s;        R=mid-l+1+q-s-ss;        return Query(k+1,mid+1,r,L,R,t-ss);    }}int main(){    int n,m,i,j;    while(~scanf("%d",&n))    {        for(i=1;i<=n;i++)        {            scanf("%d",&Tree[0][i]);            sorted[i]=Tree[0][i];        }        std::sort(sorted+1,sorted+n+1);        Build(0,1,n);        scanf("%d",&m);        int p,q,k;        while(m--)        {            scanf("%d%d%d",&p,&q,&k);            p++;q++;k--;            printf("%d\n",Query(0,1,n,p,q,q-p+1-k));        }    }    return 0;}


 

原创粉丝点击