题目:
http://poj.org/problem?id=2104
题意:
给定一个长度为n的序列,每次求出一个给定区间内的第k小数
思路:
之前用很多方法写这道题了,今天用整体二分写了一次
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
using namespace std;
typedef long long ll;
const int N = 100000 + 10, M = 5000 + 10;
struct BIT
{
int n, b[N];
void init(int _n)
{
n = _n;
memset(b, 0, sizeof b);
}
void add(int i, int x)
{
while(i <= n) b[i] += x, i += i & -i;
}
int sum(int i)
{
int ans = 0;
while(i > 0) ans += b[i], i -= i & -i;
return ans;
}
} bit;
struct node
{
int x, y, k, id, type;
void init(int _x, int _y, int _k, int _id, int _type)
{
x = _x, y = _y, k = _k, id = _id, type = _type;
}
} q[N+M], ql[N+M], qr[N+M];
int a[N], ans[M];
void divide_conquer(int st, int en, ll l, ll r)
{
if(st > en) return;
if(l == r)
{
for(int i = st; i <= en; i++)
if(q[i].type == 2) ans[q[i].id] = l;
return;
}
ll mid = (l + r) >> 1;//这个地方写成(l+r)/2可能会莫名RE
int kl = 0, kr = 0;
for(int i = st; i <= en; i++)
{
if(q[i].type == 1)
{
if(q[i].x <= mid)
{
ql[kl++] = q[i];
bit.add(q[i].id, q[i].y);
}
else qr[kr++] = q[i];
}
else
{
int num = bit.sum(q[i].y) - bit.sum(q[i].x - 1);
if(num >= q[i].k) ql[kl++] = q[i];
else
{
q[i].k -= num;
qr[kr++] = q[i];
}
}
}
for(int i = 0; i < kl; i++)
if(ql[i].type == 1) bit.add(ql[i].id, -ql[i].y);
for(int i = 0; i < kl; i++) q[st+i] = ql[i];
for(int i = 0; i < kr; i++) q[st+kl+i] = qr[i];
divide_conquer(st, st + kl - 1, l, mid);
divide_conquer(st + kl, en, mid + 1, r);
}
int main()
{
int n, m;
while(~ scanf("%d%d", &n, &m))
{
bit.init(n);
int x, y, k, tot = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
q[++tot].init(x, 1, 0, i, 1);
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &x, &y, &k);
q[++tot].init(x, y, k, i, 2);
}
divide_conquer(1, tot, INT_MIN, INT_MAX);
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
}
return 0;
}