POJ 2104 K-th Number

http://poj.org/problem?id=2104

题目

Time Limit:2s

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.

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 first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).

The second line contains n different integer numbers not exceeding 109 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

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

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

题解

求第k大的数可以直接排序$mathcal{O}(nlog n)$,或者修改一下快速排序的方法,做到$mathcal{O}(n)$,对于多组询问就没办法了,只能$mathcal{O}(nm)$显然超时

可以从值域入手,统计小于等于x的数有多少个,如果结果(ans)小于等于k,说明这个数小于等于x(可能等于x的数字不存在,导致个数没有变化),否则大于x,那么就可以进行二分,继续在左半边值域或右半边值域继续,需要注意的是如果在右半边,需要把$k-=ans$

对于多个询问,可以把在左半边值域的询问递归进左半边,右半边值域的询问递归进右半边

因为范围不同,可以用树状树组保存小于等于x的数字的位置,前缀和表示这前面有多少个小于等于x的数字,减去(左边界-1)的值就是这个区间小于等于x的数字的个数

由于数字很多,需要使用读写挂= =https://www.luogu.com.cn/blog/encore/io-you-hua-nei-suo-shi

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
using namespace std;
char buf[1<<21], *p1=buf, *p2=buf; bool beof;
#define gc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin)),(p1==p2)?EOF:*p1++)
template<class T> inline void read(T &x) {
	x=0; char ch; int si=1;
	do ch=getchar(); while(!isdigit(ch) && ch!='-');
	if(ch=='-') si=-1,ch=getchar();
	while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} x*=si;
}
#define MAXN 100007
#define MAXM 5007
#define MAXV 1000000000
struct node {
	int v, l, r, id;
} op[MAXN+MAXM], tl[MAXN+MAXM], tr[MAXN+MAXM];
int opn;
int ans[MAXM];
int bt[MAXN];
int n, m;
inline void opa(int x,int v) {
	for(;x<=n;x+=x&-x) {
		bt[x]+=v;
	}
}
inline int opq(int x) {
	int ans=0;
	for(;x>0;x-=x&-x) {
		ans+=bt[x];
	}
	return ans;
}
void calc(int l, int r, int ql, int qr) {
	if(l==r) {
		REP(i,ql,qr) if(op[i].v) {
			ans[op[i].id]=l;
		}
		return;
	}
	int m=(l+r)>>1;
	int nl=0,nr=0; bool ll=false, rr=false;
	REP(i,ql,qr) {
		if(op[i].v==0) {
			if(op[i].r<=m) opa(op[i].l,1),tl[nl++]=op[i];
			else tr[nr++]=op[i];
		} else {
			int ans=opq(op[i].r)-opq(op[i].l-1);
			if(op[i].v<=ans) tl[nl++]=op[i],ll=true;
			else {
				tr[nr]=op[i],rr=true;
				tr[nr].v-=ans;
				nr++;
			}
		}
	}
	REP(i,0,nl) if(tl[i].v==0) {
		opa(tl[i].l,-1);
	}
	opn=ql;
	REP(i,0,nl) op[opn++]=tl[i];
	REP(i,0,nr) op[opn++]=tr[i];
	if(ll) calc(l,m,ql,ql+nl);
	if(rr) calc(m+1,r,ql+nl,qr);
}
int main() {
	read(n); read(m); memset(bt,0,sizeof(int)*(n+1));
	opn=0;
	REPE(i,1,n) {
		op[opn].v=0, op[opn].l=i;
		read(op[opn].r);
		opn++;
	}
	REP(i,0,m) {
		read(op[opn].l); read(op[opn].r); read(op[opn].v); op[opn].id=i;
		opn++;
	}
	calc(-MAXV,MAXV,0,opn);
	REP(i,0,m) printf("%d
", ans[i]);
}
原文地址:https://www.cnblogs.com/sahdsg/p/12271390.html