【转载】【树状数组区间第K大/小】

原帖:http://www.cnblogs.com/zgmf_x20a/archive/2008/11/15/1334109.html

回顾树状数组的定义,注意到有如下两条性质:
一,c[ans]=sum of A[ans-lowbit(ans)+1 ... ans];
二,当ans=2^k时,
 c[ans]=sum of A[1 ... ans];

下面说明findK(k)如何运作:
1,设置边界条件ans,ans‘<maxn且cnt<=k;
2,初始化cnt=c[ans],其中ans=2^k且k为满足边界条件的最大整数;
3,找到满足边界条件的最大的ans‘使得ans‘-lowbit(ans‘)=ans,即ans‘满足c[ans‘]=A[ans+1 .. ans‘](根据性质一),只要将c[ans‘]累加到cnt中(此时cnt=sum of A[1 ... ans‘],根据性质二),cnt便可以作为k的逼近值;
4,重复第3步直到cnt已无法再逼近k,此时ans刚好比解小1,返回ans+1。

因此findk(k)的实质就是二分逼近

 1 /**********************************
 2
 3 树状数组实现查找K小的元素
 4
 5                   经典。
 6
 7 限制:数据范围在1<<20 以内
 8
 9 ***********************************/
10
11 #include <iostream>
12
13 using namespace std;
14
15
16
17 #define maxn 1<<20
18
19 int n,k;
20
21 int c[maxn];
22
23
24
25 int lowbit(int x){
26
27     return x&-x;
28
29 }
30
31
32
33 void insert(int x,int t){
34
35        while(x<maxn){
36
37           c[x]+=t;
38
39           x+=lowbit(x);
40
41        }
42
43 }
44
45 int find(int k){
46
47     int cnt=0,ans=0;
48
49     for(int i=20;i>=0;i--){
50
51         ans+=(1<<i);
52
53         if(ans>=maxn || cnt+c[ans]>=k)ans-=(1<<i);
54
55         else cnt+=c[ans];
56
57     }
58
59     return ans+1;
60
61 }
62
63 void input(){
64
65        memset(c,0,sizeof(c));
66
67        int t;
68
69        scanf("%d%d",&n,&k);
70
71        for(int i=0;i<n;i++){
72
73             scanf("%d",&t);
74
75             insert(t,1);
76
77        }
78
79        printf("%d\n",find(k));
80
81 }
82
83 int main(){
84
85     int cases;
86
87     scanf("%d",&cases);
88
89     while(cases--){
90
91         input();
92
93     }
94
95     return 0;
96
97 }

时间: 2024-10-26 23:49:04

【转载】【树状数组区间第K大/小】的相关文章

Permutation UVA - 11525(值域树状数组,树状数组区间第k大(离线),log方,log)

Permutation UVA - 11525 看康托展开 题目给出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展开(将n个数的所有排列按字典序排序,并将所有排列编号(从0开始),给出排列的编号得到对应排列)用到的式子.可以想到用逆康托展开的方法.但是需要一些变化: for(i=n;i>=1;i--) { s[i-1]+=s[i]/(n-i+1); s[i]%=(n-i+1); } 例如:n=3时,3=0*2!+0*1!+3*0!应该变为3=1

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的

hdu 2985 The k-th Largest Group 树状数组求第K大

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted: 2712 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

hdu5592/BestCoder Round #65 树状数组寻找第K大

ZYB's Premutation Memory Limit: 131072/131072 K (Java/Others) 问题描述 ZYBZYB有一个排列PP,但他只记得PP中每个前缀区间的逆序对数,现在他要求你还原这个排列. (i,j)(i < j)(i,j)(i<j)被称为一对逆序对当且仅当A_i>A_jA?i??>A?j?? 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 第一行一个正整数NN,描述排列的长度. 第二行NN个正整数A_iA?i??,描述前缀区间

POJ2985 The k-th Largest Group[树状数组求第k大值 并查集]

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8807   Accepted: 2875 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

zoj 3635 Cinema in Akiba (树状数组求第K大)

Cinema in Akiba Cinema in Akiba (CIA) is a small but very popular cinema in Akihabara. Every night the cinema is full of people. The layout of CIA is very interesting, as there is only one row so that every audience can enjoy the wonderful movies wit

树状数组求第K大(From CLJ)

int ret=0; for(int p=1<<log2[n];p;p>>=1) if(a[ret+p]<=kth) kth-=a[ret+=p]; return ret;

【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改

题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. 输入 第一行N,M接下来M行,每行形如1 a b c或2 a b c 输出 输出每个询问的结果 样例输入 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 样例输出 1 2 1 题解 整体二分+树状数组区间修改 当年naive的树套树题解 前两天由于要

树状数组求第K小值 (spoj227 Ordering the Soldiers &amp;&amp; hdu2852 KiKi&#39;s K-Number)

题目:http://www.spoj.com/problems/ORDERS/ and http://acm.hdu.edu.cn/showproblem.php?pid=2852 题意:spoj227:告诉每个位置前面有多少个数比当前位置小,求出原序列.hdu2852:设计一个容器,支持几种操作:增加/删除元素,求容器中比a大的数中第k小的数是多少. 分析:两个题思路都是求数组里面的第K小的数.开始一直在找O(N*logN)的方法,后来发现O(N*logN*logN)也是可以过的...两步:和