Section 9

master
大蒟蒻 9 years ago
parent 34c3f321e7
commit 13d625b42f

@ -0,0 +1,46 @@
#include <algorithm>
#include <cstdio>
#include <cstring>
const int N = int(1e5 + 5);
int n, a[N], b[N], idx, rt[N];
struct node
{
int ch[2], sz;
} T[N * 20];
void insert(int y, int &x, int l, int r, int p)
{
T[x = ++idx] = T[y];
T[x].sz++;
if (l == r - 1) return;
int m = (l + r) >> 1;
p < m ?
insert(T[y].ch[0], T[x].ch[0], l, m, p) :
insert(T[y].ch[1], T[x].ch[1], m, r, p);
}
int query(int nl, int nr, int l, int r, int k)
{
if (l == r - 1) return l;
int delta = T[T[nr].ch[0]].sz - T[T[nl].ch[0]].sz, m = (l + r) >> 1;
return delta >= k ?
query(T[nl].ch[0], T[nr].ch[0], l, m, k) :
query(T[nl].ch[1], T[nr].ch[1], m, r, k - delta);
}
int main()
{
int q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memcpy(b, a + 1, n << 2);
std::sort(b, b + n);
int m = int(std::unique(b, b + n) - b);
for (int i = 1; i <= n; i++)
a[i] = int(std::lower_bound(b, b + m, a[i]) - b);
for (int i = 1; i <= n; i++) insert(rt[i - 1], rt[i], 0, m, a[i]);
while (q--)
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", b[query(rt[l - 1], rt[r], 0, m, k)]);
}
return 0;
}

@ -0,0 +1,46 @@
#include <algorithm>
#include <cstdio>
#include <cstring>
const int N = int(1e5 + 5);
int n, a[N], b[N], idx, rt[N];
struct node
{
int ch[2], sz;
} T[N * 20];
void insert(int y, int &x, int l, int r, int p)
{
T[x = ++idx] = T[y];
T[x].sz++;
if (l == r - 1) return;
int m = (l + r) >> 1;
p < m ?
insert(T[y].ch[0], T[x].ch[0], l, m, p) :
insert(T[y].ch[1], T[x].ch[1], m, r, p);
}
int query(int nl, int nr, int l, int r, int k)
{
if (l == r - 1) return l;
int delta = T[T[nr].ch[0]].sz - T[T[nl].ch[0]].sz, m = (l + r) >> 1;
return delta >= k ?
query(T[nl].ch[0], T[nr].ch[0], l, m, k) :
query(T[nl].ch[1], T[nr].ch[1], m, r, k - delta);
}
int main()
{
int q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memcpy(b, a + 1, n << 2);
std::sort(b, b + n);
int m = int(std::unique(b, b + n) - b);
for (int i = 1; i <= n; i++)
a[i] = int(std::lower_bound(b, b + m, a[i]) - b);
for (int i = 1; i <= n; i++) insert(rt[i - 1], rt[i], 0, m, a[i]);
while (q--)
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", b[query(rt[l - 1], rt[r], 0, m, k)]);
}
return 0;
}

@ -593,4 +593,11 @@ Manacher 模板题
\subsubsection{练习题}
\paragraph{BZOJ1588 营业额统计} 其实可以用\verb|std::set|水过去。
\codeinput[\href{http://www.lydsy.com/JudgeOnline/problem.php?id=1588}{BZOJ1588} - 营业额统计]{assets/day10/bzoj1588.cpp}
\subsection{主席树}
\paragraph{前导知识} 只要会线段树就行
\paragraph{简介} 主席树是一系列差分后的线段树。
\paragraph{示例代码} 模板题
\codeinput[\href{http://poj.org/problem?id=2104}{POJ2104} - K-th Number]{assets/day10/poj2104.cpp}
\paragraph{分析}
首先,主席树里面的线段树是一堆“权值线段树”,所谓权值线段树,就是维护各个值的信息。与一般的线段树维护的东西不同,一般的线段树维护的是位置上的信息,例如这个位置上值为多少,这段区间的最大值/和是多少一类的;而权值线段树维护的是这个值出现了几次之类的信息,如果看的更长远一些,我们可以认为普通线段树是维护的时域上的信息,而权值线段树是维护的频域上的信息,当然都是离散的。这个题给出了一个序列,第一步将其离散化,第二步将每一个数依次插入一棵与之前的线段树有公用节点的新线段树的这个点的大小所代表的位置上,这样就可以看作将时域信息转成频域信息了。然后在指定区间的线段树之差上“二分”,其实就是在线段树上按照大小移动,然后输出就行了。
\end{document}
Loading…
Cancel
Save