Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 40920 | Accepted: 13367 | |
Case Time Limit: 2000MS |
Description
Input
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
算法及题目分析:给你一个具有n个数字的数组,进行m此询问。每次询问,都会给你一个子区间,问你这个区间内的第k大的数字是多少?例如:数组序列(下标从1开始)是:1 5 2 6 3 7 4, 询问:[2, 5]的第3大的数字。[2, 5]区间的数是:5 2 6 3,排序后:2 3 5 6,第3大的数应该是5. 但是当数据量比较庞大的时候,询问次数比较多的时候,这种常规算法思想实现起来之星效率比较低。于是一种树型结构算法应运而生:【划分树算法】(基于线段树思想)(划分树实现细节有待补充)。【可以参考:程序设计 解题策略 吴永辉 王建德 编著 P2】
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> #define N 100000+10 using namespace std; //POJ 2104 int tree[50][N];//tree[p][i]表示第p层中第i的位置的值 int sorted[N]; int toleft[50][N];//toleft[p][i]表示第p层从1到i中有 //多少个数被划分入下一层的左子区间 //划分树建树的实现过程 void build(int ll ,int r, int dep) { if(ll==r) return; //递归出口 若划分至叶子,则回溯 int mid=(ll+r)>>1; //等于(l+r)/2 计算区间的中间指针 int same=mid-ll+1; //计算[l,r]被分入下层左区间的个数 for(int i=ll; i<=r; i++) { if(tree[dep][i] < sorted[mid]) same--; } int llpos=ll; int rpos=mid+1; for(int i=ll; i<=r; i++) { if(tree[dep][i] < sorted[mid]) tree[dep+1][llpos++]=tree[dep][i]; else if(tree[dep][i]==sorted[mid] && same>0 ) { tree[dep+1][llpos++]=tree[dep][i]; same--; } else tree[dep+1][rpos++]=tree[dep][i]; toleft[dep][i]=toleft[dep][ll-1] +llpos-ll; } build(ll, mid, dep+1);//递归计算下一层的左子区间 build(mid+1, r, dep+1);//递归计算下一层的右子区间 } int query(int L, int R, int ll, int r, int dep, int k) //从划分数的dep层出发 自上而下的在大区间[L,R]里查询子区间 //[ll,r]中第K大的数 { if(ll==r) return tree[dep][ll]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][ll-1]; if(cnt >= k) { int newll=L+toleft[dep][ll-1]-toleft[dep][L-1]; int newr = newll+cnt-1; return query(L, mid, newll, newr, dep+1, k); } else { int newr=r+toleft[dep][R]-toleft[dep][r]; int newll=newr-(r-ll-cnt); return query(mid+1, R, newll, newr, dep+1, k-cnt); } } int main() { int n, m; int i; while(~scanf("%d %d", &n, &m)) { for(i=1; i<=n; i++)//n { scanf("%d", &tree[0][i]);// sorted[i]=tree[0][i]; } sort(sorted+1,sorted+n+1); build(1, n, 0);//建立划分树 while(m--) { int u, v, w; scanf("%d %d %d", &u, &v, &w); printf("%d\n", query(1, n, u, v, 0, w)); } } return 0; }