在学完一些前置技能后开始学主席树了owo
对于某一个序列[1, n]考虑对其每一个前缀[1, i]建立一棵权值线段树 则其值是可减的
直接建立线段树空间复杂度是
O(n2log(n))
O
(
n
2
l
o
g
(
n
)
)
的, 无法承受
考虑每一个点的更改只会影响
log(n)
l
o
g
(
n
)
个点的权值
动态开点+利用一些相同信息就能开下了
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
using namespace std;
const int maxn = 2e5 + 10;
tr1::unordered_map<int, int> id;
int rel[maxn], root[maxn];
int n, q, m, x, y, k;
struct Fuck
{
int x, num;
}a[maxn];
bool cmp1(Fuck A, Fuck B)
{
return A.x < B.x;
}
bool cmp2(Fuck A, Fuck B)
{
return A.num < B.num;
}
namespace Chairman_Tree
{
int cnt;
struct node
{
int ls, rs, sum;
}T[maxn * 50];
void pushup(int x)
{
T[x].sum = T[T[x].ls].sum + T[T[x].rs].sum;
}
void build(int &x, int l, int r)
{
T[x = ++ cnt].sum = 0;
if(l == r)
return;
int mid = ((l + r) >> 1);
build(T[x].ls, l, mid);
build(T[x].rs, mid + 1, r);
}
void update(int &x, int pre, int l, int r, int p)
{
T[x = ++ cnt] = T[pre];
if(l == p && r == p)
++ T[x].sum;
else
{
int mid = ((l + r) >> 1);
if(p <= mid)
update(T[x].ls, T[pre].ls, l, mid, p);
else
update(T[x].rs, T[pre].rs, mid + 1, r, p);
pushup(x);
}
}
int query(int x, int pre, int l, int r, int p)
{
if(l == r) return l;
int mid = ((l + r) >> 1), S = T[T[x].ls].sum - T[T[pre].ls].sum;
if(S >= p) return query(T[x].ls, T[pre].ls, l, mid, p);
return query(T[x].rs, T[pre].rs, mid + 1, r, p - S);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3834.in", "r", stdin);
freopen("3834.out", "w", stdout);
#endif
scanf("%d%d", &n, &q);
For(i, 1, n)
scanf("%d", &a[i].x), a[i].num = i;
sort(a + 1, a + n + 1, cmp1);
For(i, 1, n)
if(!id[a[i].x])
rel[id[a[i].x] = ++ m] = a[i].x;
sort(a + 1, a + n + 1, cmp2);
Chairman_Tree::build(root[0], 1, m);
For(i, 1, n)
Chairman_Tree::update(root[i], root[i - 1], 1, m, id[a[i].x]);
while(q --)
{
scanf("%d%d%d", &x, &y, &k);
printf("%d\n", rel[Chairman_Tree::query(root[y], root[x - 1], 1, m, k)]);
}
return 0;
}