POJ 2104 K-th Number (划分树 函数式线段树)

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

题意:给出一个数列,若干询问L,R,K,询问区间[L,R]之间的第K小的数。

思路:划分树,函数式线段树

 //划分树

 #include <iostream>

 #include <cstdio>

 #include <algorithm>

 using namespace std;

 

 

 const int MAX=100005;

 

 struct Node

 {

     int L,R;

 };

 

 struct HuaFen_tree

 {

     Node a[MAX<<2];

     int s[MAX],t[35][MAX],tot[35][MAX];

 

     void input(int n)

     {

         int i;

         for(i=1;i<=n;i++)

         {

             scanf("%d",&s[i]);

             t[1][i]=s[i];

         }

         sort(s+1,s+n+1);

     }

     void build(int dep,int u,int L,int R)

     {

         a[u].L=L;

         a[u].R=R;

         if(L==R) return;

         int i,mid=(L+R)>>1;

         int sameNum=mid-L+1;

         for(i=L;i<=R;i++) if(t[dep][i]<s[mid]) sameNum--;

         int LL=L,LR=mid,RL=mid+1,RR=R;

         int Lnum=0,Rnum=0;

         for(i=L;i<=R;i++)

         {

             if(i==L) tot[dep][i]=0;

             else tot[dep][i]=tot[dep][i-1];

             if(t[dep][i]<s[mid])

             {

                 tot[dep][i]++;

                 t[dep+1][LL+Lnum]=t[dep][i];

                 Lnum++;

             }

             else if(t[dep][i]>s[mid])

             {

                 t[dep+1][RL+Rnum]=t[dep][i];

                 Rnum++;

             }

             else

             {

                 if(sameNum>0)

                 {

                     sameNum--;

                     tot[dep][i]++;

                     t[dep+1][LL+Lnum]=t[dep][i];

                     Lnum++;

                 }

                 else

                 {

                     t[dep+1][RL+Rnum]=t[dep][i];

                     Rnum++;

                 }

             }

         }

         build(dep+1,u<<1,LL,LR);

         build(dep+1,u<<1|1,RL,RR);

     }

 

     //在区间[a[u].L,a[u].R]这个区间中查找[L,R]中的第K大值

     int query(int dep,int u,int L,int R,int K)

     {

         if(L==R) return t[dep][L];

         int x,y,xx,yy,_L,_R,mid=(a[u].L+a[u].R)>>1;

         if(L==a[u].L) x=0;

         else x=tot[dep][L-1]; //x为[a[u].L,L-1]中分到左边的

         y=tot[dep][R]-x;      //y为[L,R]中分到左边的

         if(y>=K)

         {

             _L=a[u].L+x;

             _R=a[u].L+x+y-1;

             return query(dep+1,u<<1,_L,_R,K);

         }

         else

         {

             xx=L-a[u].L-x;  //xx是[a[u].L,L-1]中分到右边的

             yy=R-L+1-y;     //yy是[L,R]中分到右边的

             _L=mid+1+xx;

             _R=mid+1+xx+yy-1;

             return query(dep+1,u<<1|1,_L,_R,K-y);

         }

     }

 };

 

 HuaFen_tree a;

 int n,m;

 

 

 int main()

 {

     while(scanf("%d%d",&n,&m)!=-1)

     {

         a.input(n);

         a.build(1,1,1,n);

         int ans,L,R,K;

         while(m--)

         {

             scanf("%d%d%d",&L,&R,&K);

             ans=a.query(1,1,L,R,K);

             printf("%d\n",ans);

         }

     }

     return 0;

 }



//函数式线段树

#include <iostream>

#include <cstdio>

#include <string.h>

#include <algorithm>

using namespace std;



struct node

{

    int a,b,L,R,s,mid;

};



const int MAX=3000000;

const int M=100005;

node t[MAX];

int root[M],tot;

int p[M],q[M],n,m;



int find(int low,int high,int p[],int key)

{

    int mid;

    while(low<=high)

    {

        mid=(low+high)>>1;

        if(p[mid]==key) break;

        if(p[mid]>key) high=mid-1;

        else low=mid+1;

    }

    return mid;

}



int build(int a,int b)

{

    int k=++tot;

    t[k].a=a;

    t[k].b=b;

    t[k].s=0;

    t[k].mid=(a+b)/2;

    if(a!=b)

    {

        t[k].L=build(a,t[k].mid);

        t[k].R=build(t[k].mid+1,b);

    }

    return k;

}



int change(int p,int x,int s)

{

    int k=++tot;

    t[k]=t[p];

    t[k].s+=s;

    if(t[k].a==x&&t[k].b==x) return k;

    if(x<=t[k].mid) t[k].L=change(t[p].L,x,s);

    else t[k].R=change(t[p].R,x,s);

    return k;

}



int query(int p,int q,int k)

{

    if(t[q].a==t[q].b) return t[q].a;

    int x=t[t[q].L].s-t[t[p].L].s;

    if(k<=x) return query(t[p].L,t[q].L,k);

    return query(t[p].R,t[q].R,k-x);

}



int main()

{

    while(scanf("%d%d",&n,&m)!=-1)

    {

        tot=0;

        int i,k;

        for(i=1;i<=n;i++)

        {

            scanf("%d",p+i);

            q[i]=p[i];

        }

        sort(q+1,q+n+1);

        k=unique(q+1,q+n+1)-(q+1);

        for(i=1;i<=n;i++) p[i]=find(1,k,q,p[i]);

        root[0]=build(1,k);

        for(i=1;i<=n;i++) root[i]=change(root[i-1],p[i],1);

        int L,R;

        while(m--)

        {

            scanf("%d%d%d",&L,&R,&k);

            printf("%d\n",q[query(root[L-1],root[R],k)]);

        }

    }

    return 0;

}

  

你可能感兴趣的:(number)