您的位置:首页 > 其它

pku2761区间第k大数-二分+树状数组

2011-08-06 21:22 441 查看
http://poj.org/problem?id=2761

题意:给定一个数组,求一些区间的第k大数,数据比2104大10倍,开始没怎么看题,直接贴代码tle了。。。这题有一个很重要的限制,那就是不存在包含关系的区间。。。

分析:那个限制条件是关键。。。在那个限制条件下,我们能很自然的想到对查询排序,从从前往后扫,逐渐加点,删点。。。。剩下的工作就和xmu那题一样了。。。。

注意用树状数组需要先离散化。。。

代码:

#include<algorithm>
#include<iostream>
#include<map>
using namespace std;

const int N=100010;
int sum
, ans
, c
, n, m;//c存离散化后某个值对应的真值
struct lisan
{
int i, ii, v; //ii为原来数组的序号,i为离散化后的值
}b
;
struct node
{
int l, r, k, i;
} a
;
int cmp2(const lisan &a, const lisan &b)
{
return a.ii<b.ii;
}
int cmp1(const lisan &a, const lisan &b)
{
return a.v<b.v;
}
int cmp(const node &a, const node &b)
{
return a.l < b.l;
}

void update(int i, int v)
{
for(; i<=n; i+=i&(-i))
sum[i] += v;
}
int query(int i)
{
int tmp=0;
for(; i>0; i-=i&(-i))
tmp += sum[i];
return tmp;
}

int bs(int k)
{
int l=1,r=n, mid, tmp;
while(l<=r)
{
mid = (l+r)>>1;
tmp = query(mid);
if(tmp>=k)
r = mid-1;
else
l = mid+1;
}
return c[l];
}

int main()
{
int i, j, ll, rr;
while(scanf("%d%d", &n, &m)!=EOF)
{
for(i=1; i<=n; i++)
{
scanf("%d", &b[i].v);
b[i].ii = i;
}
sort(b+1, b+n+1, cmp1);
b[1].i = 1;
c[1] = b[1].v;
for(i=1, j=1; i<=n; i++)
{
if(b[i].v!=b[i-1].v)
b[i].i = ++j;
else
b[i].i = j;
c[j] = b[i].v;
}
sort(b+1, b+n+1, cmp2);
for(i=1; i<=n; i++)
sum[i] = 0;
for(i=0; i<m; i++)
{
scanf("%d%d%d",&a[i].l, &a[i].r, &a[i].k);
a[i].i = i;
}
sort(a, a+m, cmp);

ll = rr = 1;
for(i=0; i<m; i++)
{
while(rr<=a[i].r)
{
update(b[rr].i, 1);
rr++;
}

while(ll<a[i].l)
{
update(b[ll].i, -1);
ll++;
}
ans[a[i].i] = bs(a[i].k);
}
for(i=0; i<m; i++)
printf("%d\n", ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: