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();
    }
}

这里写图片描述

转载于:https://www.cnblogs.com/SiriusRen/p/6532262.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值