如题:http://poj.org/problem?id=2104
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 39943 | Accepted: 13042 | |
Case Time Limit: 2000MS |
Description
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The second line contains n different integer numbers not exceeding 10 9 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
Source
题意很简单,求闭区间内的第k大的数。
思路:关于区间的算法,我能想到的只有线段树,怎么更改线段树的区间的操作,查询才能满足这一道题。
1.首先,建树,每一个区间是一个排好序的数组,记录的是这个区间所有元素从小到大排列。建树的过程和归并排序的过程非常相似。建好子树后,对父节点进行更新,也就是对两个儿子的数组进行从小到大的合并、
2.开一个数组num 它是输入的N个数,并把它排序。
3.我们想想看,假设一个区间的第k大的那个数是x,也就是说要这个区间里小于等于x个数不超过k个。那么思路来了,我们枚举x(二分,初始lb=-1,rb=n(尽量取取不到的值))(x∈num数组),判断在给出区间内不超过x的数的个数,如果这个返回的个数>=k,也就是说这个枚举的x(num[mid])还偏小,让rb=mid,继续搜索,反之,lb=mid。
判断这个区间内不小于x的数的个数就要用到线段树了,如果当前搜索的区间和给出区间没有交集,返回0.如果有交集,搜索有交集的子区间。累加返回。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100005
int n,m;
int nums[MAXN];
struct node
{
int l,r;
int *a;
};
node tree[MAXN*4];
void push_up(int p)
{
int len=tree[p].r-tree[p].l+1;
tree[p].a=new int[len];
int p1=0,p2=0;
int len1=tree[p*2].r-tree[p*2].l+1;
int len2=tree[p*2+1].r-tree[p*2+1].l+1;
int m=0;
while(p1<len1&&p2<len2)
{
if(tree[p*2].a[p1]<tree[p*2+1].a[p2])
tree[p].a[m++]=tree[p*2].a[p1++];
else
tree[p].a[m++]=tree[p*2+1].a[p2++];
}
int i;
if(p1<len1)
for(i=p1;i<len1;i++)
tree[p].a[m++]=tree[p*2].a[i];
else
for(i=p2;i<len2;i++)
tree[p].a[m++]=tree[p*2+1].a[i];
}
int c=0;
void build(int p,int l,int r)
{
tree[p].l=l;
tree[p].r=r;
if(l==r)
{
tree[p].a=new int[1];
scanf("%d",&tree[p].a[0]);
nums[c++]=tree[p].a[0];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
push_up(p);
}
int query(int p,int l,int r,int x)
{
if(tree[p].l>r||tree[p].r<l)
return 0;
if(tree[p].l==l&&tree[p].r==r)
{
int len=tree[p].r-tree[p].l+1;
return upper_bound(tree[p].a,tree[p].a+len,x)-tree[p].a;
}
int mid=(tree[p].l+tree[p].r)/2;
if(l>mid)
return query(p*2+1,l,r,x);
else if(r<=mid)
return query(p*2,l,r,x);
else
{
int lc=query(p*2,l,mid,x);
int rc=query(p*2+1,mid+1,r,x);
return lc+rc;
}
}
int main()
{
// freopen("C:\\1.txt","r",stdin);
cin>>n>>m;
build(1,1,n);
sort(nums,nums+n);
while(m--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
int lb=-1,rb=n;
while(rb-lb>1)
{
int md=(rb+lb)/2;
int res=query(1,l,r,nums[md]); //查询[l,r]中不超过nums[md]的个数.
if(res>=k)
rb=md;
else
lb=md;
}
printf("%d\n",nums[rb]);
}
return 0;
}