HDU2665 kth number 线段树做法

题意:求区间第k小
思路:
线段树 每个节点上保存 当前区间已经排序好的序列

(归并一下就好了嘛 复杂度 O(l)的)
这样建树的时空复杂度都是 O(nlogn)的

对于 每次询问 二分一个答案
在树上upper_bound一下 判断一下

这样 查询的复杂度 就成O(m*log(inf) * log(n) * log(n))的了

就酱~
但是POJ死也卡不过去……桑心

//By SiriusRen
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100010
vector<int>tree[N*4];
int n,m,q,xx,yy,zz,Mid,b[N],c[N],cases;
void insert(int l,int r,int pos){
    if(l==r){tree[pos].push_back(lower_bound(c+1,c+1+n,b[l])-c);return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    insert(l,mid,lson),insert(mid+1,r,rson);
}
void add(int l,int r,int pos){
    if(l==r)return;
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    add(l,mid,lson),add(mid+1,r,rson);
    tree[pos].resize(tree[lson].size()+tree[rson].size());
    merge(tree[lson].begin(),tree[lson].end(),tree[rson].begin(),tree[rson].end(),tree[pos].begin());
}
int query(int l,int r,int pos){
    if(l>=xx&&r<=yy)return upper_bound(tree[pos].begin(),tree[pos].end(),Mid)-tree[pos].begin();
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<xx)return query(mid+1,r,rson);
    else if(mid>=yy)return query(l,mid,lson);
    else return query(l,mid,lson)+query(mid+1,r,rson);
}
int main(){
    scanf("%d",&cases);
    while(cases--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]),c[i]=b[i];
        sort(c+1,c+1+n);
        insert(1,n,1),add(1,n,1);
        while(m--){
            scanf("%d%d%d",&xx,&yy,&zz);
            int l=0,r=100000,answer;
            while(l<=r){
                Mid=(l+r)>>1;
                int T=query(1,n,1);
                if(T>=zz)answer=Mid,r=Mid-1;
                else l=Mid+1;
            }
            printf("%d\n",c[answer]);
        }
        for(int i=1;i<=4*N;i++)tree[i].clear();
    }
}

这里写图片描述

posted @ 2016-10-10 23:15  SiriusRen  阅读(130)  评论(0编辑  收藏  举报