这道题刚开始是用quickselect做的,由于每次都要复制到一个新数组并partition,不出意料地超时了。然后看到discuss中提到划分树。用了很久才大致明白是什么意思。这里对其基本思想有很好的描述:http://blog.renren.com/blog/367737224/728617495。但是划分树的更新区间的index还是很难的。几次修改之后就和网上的代码完全一致了。比较好的链接是:http://www.cnblogs.com/yym2013/p/3714654.html和http://www.cnblogs.com/kane0526/archive/2013/04/20/3033212.html。也至少是明白代码含义了,还需要好好练练。
2104 | Accepted | 15624K | 1266MS | G++ | 3201B |
/*
ID: thestor1
LANG: C++
TASK: poj2104
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
const int MAXN = 100500;
int sorted[MAXN];
int nums[20][MAXN];
int leftsize[20][MAXN];
void build(int layer, int left, int right)
{
// cout << "[build]layer: " << layer << ", left: " << left << ", right: " << right << endl;
int mid = left + ((right - left) >> 1);
int pivot = sorted[mid];
int nsame = mid - left + 1;
for (int i = left; i <= mid; ++i)
{
if (sorted[i] < pivot)
{
nsame--;
}
}
int nextleft = left, nextright = mid + 1;
for (int i = left; i <= right; ++i)
{
if (i == left)
{
leftsize[layer][i] = 0;
}
else
{
leftsize[layer][i] = leftsize[layer][i - 1];
}
if (nums[layer][i] < pivot || (nums[layer][i] == pivot && nsame >= 1))
{
nums[layer + 1][nextleft] = nums[layer][i];
nextleft++;
leftsize[layer][i]++;
if (nums[layer][i] == pivot)
{
nsame--;
}
}
else
{
assert (nums[layer][i] > pivot || nsame == 0);
nums[layer + 1][nextright] = nums[layer][i];
nextright++;
}
}
assert (nextleft == mid + 1 && nextright == right + 1);
if (left == right)
{
return;
}
build(layer + 1, left, mid);
build(layer + 1, mid + 1, right);
}
int query(int layer, int left, int right, int queryleft, int queryright, int k)
{
// cout << "[query]layer: " << layer << ", left: " << left << ", right: " << right << ", queryleft: " << queryleft << ", queryright: " << queryright << ", k: " << k << endl;
assert (left <= queryleft && queryright <= right);
if (left == right)
{
assert (k == 1 && queryleft == queryright && queryright == left);
return nums[layer][left];
}
int mid = left + ((right - left) >> 1);
// s is the number of nums in left subtree in range [left, queryleft - 1]
// ss is the number of nums in left subtree in range [queryleft, queryright]
int s, ss;
if (queryleft == left)
{
s = 0;
ss = leftsize[layer][queryright];
}
else
{
s = leftsize[layer][queryleft - 1];
ss = leftsize[layer][queryright] - s;
}
if (ss >= k)
{
// the kth number in [queryleft, queryright] is in the left subtree
// cout << "[debug]go left" << endl;
return query(layer + 1, left, mid, left + s, left + s + ss - 1, k);
}
else
{
// cout << "[debug]go right" << endl;
return query(layer + 1, mid + 1, right, mid + 1 + queryleft - 1 - left + 1 - s, mid + 1 + queryright - left + 1 - s - ss - 1, k - ss);
}
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
{
scanf("%d", &nums[0][i + 1]);
sorted[i + 1] = nums[0][i + 1];
}
sort(sorted + 1, sorted + n + 1);
build(0, 1, n);
int queryleft, queryright, k;
for (int i = 0; i < m; ++i)
{
scanf("%d%d%d", &queryleft, &queryright, &k);
printf("%d\n", query(0, 1, n, queryleft, queryright, k));
}
return 0;
}