Section 9.1.1-3

master
大蒟蒻 9 years ago
parent c38bf58786
commit 3aba88d3ed

@ -0,0 +1,195 @@
#include <cstdio>
#include <cstdlib>
#define sz(x) (x == 0 ? 0 : x->size)
#define update(x) \
if (x) x->size = sz(x->child[0]) + sz(x->child[1]) + 1
#define getVal(x) (x == 0 ? 0 : x->val)
typedef int valType;
const int arrSize = 100005;
struct Node
{
valType val;
int size;
Node *child[2], *father;
Node *Init(int x, Node *f)
{
val = x, size = 1, father = f, child[0] = child[1] = 0;
return this;
}
};
typedef Node *lpNode;
template <typename _ty, typename _typ = _ty *>
struct allocator
{
private:
int i;
_ty *data;
_typ *pt;
public:
allocator(int size)
{
data = new _ty[size];
pt = new _typ[size];
this->i = 0;
for (int j = 0; j < size; j++) pt[j] = &data[j];
}
_typ alloc()
{
return pt[i++];
}
void free(_typ ptr)
{
pt[--i] = ptr;
}
};
struct SplayTree
{
private:
lpNode root = 0;
allocator<Node> *mem;
void rotate(lpNode x)
{
if (x == 0 || x->father == 0) return;
int d = (x == x->father->child[0]);
lpNode y = x->father;
y->child[d ^ 1] = x->child[d];
if (x->child[d]) x->child[d]->father = y;
x->father = y->father;
if (y->father) y->father->child[y == y->father->child[1]] = x;
y->father = x;
x->child[d] = y;
update(y);
update(x);
}
void Splay(lpNode x, lpNode &target)
{
lpNode targetFather = target->father;
while (x->father != targetFather)
if (x->father == target)
rotate(x);
else if ((x->father->father->child[0] == x->father) == (x->father->child[0] == x))
rotate(x->father), rotate(x);
else
rotate(x), rotate(x);
target = x;
}
lpNode find(int x)
{
lpNode s = root;
while (true)
if (s == 0)
return 0;
else if (s->val == x)
{
Splay(s, root);
return s;
}
else
s = s->child[x > s->val];
}
lpNode join(lpNode x, lpNode y)
{
if (x == 0)
return y;
else
{
lpNode m = max_min(x, 1);
Splay(m, x);
m->child[1] = y;
if (y) y->father = m;
update(m);
return x;
}
}
public:
SplayTree(int _)
{
mem = new allocator<Node>(_);
}
lpNode max_min(lpNode x, int i)
{
while (x && x->child[i]) x = x->child[i];
return x;
}
void insert(int x)
{
if (root == 0)
root = mem->alloc()->Init(x, 0);
else
{
lpNode s = root, p = 0;
while (s)
p = s, s = s->child[x > s->val];
s = mem->alloc()->Init(x, p);
p->child[x > p->val] = s;
Splay(s, root);
}
}
void remove(int x)
{
lpNode p = find(x);
if (p)
{
root = join(p->child[0], p->child[1]);
root->father = 0;
mem->free(p);
}
}
int rank(int x)
{
lpNode s = root;
int ans = 0;
while (s)
if (x <= s->val)
s = s->child[0];
else
ans = ans + 1 + sz(s->child[0]), s = s->child[1];
return ans + 1;
}
lpNode select(int x)
{
lpNode s = root;
while (s)
if (x == sz(s->child[0]) + 1)
return s;
else if (x <= sz(s->child[0]))
s = s->child[0];
else
x = x - 1 - sz(s->child[0]), s = s->child[1];
}
lpNode near(int x, int d)
{
lpNode s = root, ans = 0;
while (s)
if (d ? s->val > x : s->val < x)
ans = s, s = s->child[d ^ 1];
else
s = s->child[d];
return ans;
}
};
int main()
{
SplayTree st(arrSize);
int n, op, num;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d%d", &op, &num);
if (op == 1)
st.insert(num);
else if (op == 2)
st.remove(num);
else if (op == 3)
printf("%d\n", st.rank(num));
else if (op == 4)
printf("%d\n", getVal(st.select(num)));
else if (op == 5)
printf("%d\n", getVal(st.near(num, 0)));
else if (op == 6)
printf("%d\n", getVal(st.near(num, 1)));
}
return 0;
}

@ -0,0 +1,150 @@
#include <cstdio>
#include <cstdlib>
#define sz(x) ((x) == 0 ? 0 : (x)->sz)
template <typename T>
struct Allocator
{
int idx;
T *data;
T **ptr;
Allocator(int size)
{
idx = 0;
data = new T[size];
ptr = new T *[size];
for (int i = 0; i < size; i++) ptr[i] = &data[i];
}
~Allocator()
{
delete[] data;
delete[] ptr;
}
T *alloc() { return ptr[idx++]; }
void free(T *pt) { ptr[--idx] = pt; }
};
struct Treap
{
typedef struct Node
{
int val, pri, sz;
Node *ch[2];
void Init(int x = 0)
{
pri = rand();
ch[0] = ch[1] = 0;
val = x;
sz = 1;
}
void update()
{
sz = 1 + sz(ch[0]) + sz(ch[1]);
}
} * lpNode;
Treap(int max_size, int _seed)
{
srand(_seed);
alloc = new Allocator<Node>(max_size);
root = 0;
}
void ins(int x)
{
insert(root, x);
}
void del(int x)
{
remove(root, x);
}
int rnk(int x)
{
int ans = 1;
lpNode cur = root;
while (cur)
if (x <= cur->val)
cur = cur->ch[0];
else
ans += sz(cur->ch[0]) + 1, cur = cur->ch[1];
return ans;
}
int kth(int x)
{
lpNode cur = root;
while (cur)
if (x == sz(cur->ch[0]) + 1)
return cur->val;
else if (x <= sz(cur->ch[0]))
cur = cur->ch[0];
else
x -= sz(cur->ch[0]) + 1,
cur = cur->ch[1];
return 0;
}
private:
Allocator<Node> *alloc;
lpNode root;
void rotate(lpNode &node, int d)
{
if (node == 0) return;
lpNode ch = node->ch[d ^ 1];
if (ch)
{
node->ch[d ^ 1] = ch->ch[d];
ch->ch[d] = node;
node = ch;
node->ch[d]->update();
node->update();
}
}
void insert(lpNode &node, int x)
{
if (node == 0)
(node = alloc->alloc())->Init(x);
else
{
int cmp = x < node->val;
insert(node->ch[cmp ^ 1], x);
node->update();
if (node->ch[cmp ^ 1]->pri < node->pri) rotate(node, cmp);
}
}
void remove(lpNode &node, int x)
{
if (node == 0)
return;
else
{
if (x < node->val)
remove(node->ch[0], x);
else if (x > node->val)
remove(node->ch[1], x);
else if (node->ch[0] == 0)
node = node->ch[1];
else if (node->ch[1] == 0)
node = node->ch[0];
else
{
int d = node->ch[0]->pri < node->ch[1]->pri;
rotate(node, d);
remove(node->ch[d], x);
}
if (node) node->update();
}
}
};
int main()
{
Treap T(100005, 3224);
int n;
scanf("%d", &n);
for (int i = 0, op, x; i < n; i++)
{
scanf("%d%d", &op, &x);
if (op == 1) T.ins(x);
if (op == 2) T.del(x);
if (op == 3) printf("%d\n", T.rnk(x));
if (op == 4) printf("%d\n", T.kth(x));
if (op == 5) printf("%d\n", T.kth(T.rnk(x) - 1));
if (op == 6) printf("%d\n", T.kth(T.rnk(x + 1)));
}
return 0;
}

@ -334,7 +334,7 @@ Manacher 模板题
\paragraph{练习题} \paragraph{练习题}
\subparagraph{\href{http://poj.org/problem?id=1284}{POJ1284} - Primitive Roots} 如果$n\in\mathbb{N_+}$有一个原根,那么$n$一共有$\varphi(\varphi(n))$个不同余的原根 \subparagraph{\href{http://poj.org/problem?id=1284}{POJ1284} - Primitive Roots} 如果$n\in\mathbb{N_+}$有一个原根,那么$n$一共有$\varphi(\varphi(n))$个不同余的原根
\codeinput[Primitive Roots]{assets/day3/poj1284.cpp} \codeinput[Primitive Roots]{assets/day3/poj1284.cpp}
\section{数据结构} \section{数据结构 I}
\subsection{树状数组}$\lg{n}$的时间内更新或查询$\sum\limits_{i=1}^n a_i$ \subsection{树状数组}$\lg{n}$的时间内更新或查询$\sum\limits_{i=1}^n a_i$
\paragraph{lowbit} \verb|lowbit(x) = x & -x| \paragraph{lowbit} \verb|lowbit(x) = x & -x|
\paragraph{两个操作} $\lg{n}$更新或查询 \paragraph{两个操作} $\lg{n}$更新或查询
@ -492,7 +492,7 @@ Manacher 模板题
\subsection{最小费用最大流} 每次找到一条最短的路增广大体上与Dinic完全相同不过总感觉很奇怪包括没有了cur多出了vis等一些不同并且不加就会爆炸。 \subsection{最小费用最大流} 每次找到一条最短的路增广大体上与Dinic完全相同不过总感觉很奇怪包括没有了cur多出了vis等一些不同并且不加就会爆炸。
\codeinput[\href{http://poj.org/problem?id=2135}{POJ2135} - Farm Tour]{assets/day6/poj2135.cpp} \codeinput[\href{http://poj.org/problem?id=2135}{POJ2135} - Farm Tour]{assets/day6/poj2135.cpp}
\paragraph{后记} 我多次尝试直接移植dinic的模板来解决最小费用最大流问题不过最后都只是收获了一个个RE看来直接照抄dinic的代码是不行的仍然要加上vis数组之类的东西来保证不会爆栈虽然我觉得我的移植代码也不会爆栈如果哪名巨佬在Review我的代码时发现了方法请不吝告知蒟蒻万分感谢。 \paragraph{后记} 我多次尝试直接移植dinic的模板来解决最小费用最大流问题不过最后都只是收获了一个个RE看来直接照抄dinic的代码是不行的仍然要加上vis数组之类的东西来保证不会爆栈虽然我觉得我的移植代码也不会爆栈如果哪名巨佬在Review我的代码时发现了方法请不吝告知蒟蒻万分感谢。
\section{XJB算法合集1} XJB算法的时间复杂度均为$O(\mbox{跑得过})$,空间复杂度均为$)(\mbox{开的下})$ \section{XJB算法合集 I} XJB算法的时间复杂度均为$O(\mbox{跑得过})$,空间复杂度均为$)(\mbox{开的下})$
\subsection{二分与三分} \subsection{二分与三分}
\paragraph{二分} 玄学算法之一,什么都可以往上套,会使时间复杂度乘上$\log{n}$。但是二分法仅适用于求解具有单调性的问题所以做题前要大胆猜想buyong求证。 \paragraph{二分} 玄学算法之一,什么都可以往上套,会使时间复杂度乘上$\log{n}$。但是二分法仅适用于求解具有单调性的问题所以做题前要大胆猜想buyong求证。
\paragraph{二分的写法} \paragraph{二分的写法}
@ -555,7 +555,7 @@ Manacher 模板题
\section{分治} 把问题分割成更小的子问题递归求解,再处理不同子问题之间的部分,这种算法设计方法就是分治法。关于分治类算法的时间复杂度,算法导论上详细的介绍了专有结论:主定理。在此不再赘述。 \section{分治} 把问题分割成更小的子问题递归求解,再处理不同子问题之间的部分,这种算法设计方法就是分治法。关于分治类算法的时间复杂度,算法导论上详细的介绍了专有结论:主定理。在此不再赘述。
\subsection{序列上的分治} \subsection{序列上的分治}
数列的逆序对数除了使用数据结构外,也可以在归并排序的基础上统计额外信息来求得。\\ 数列的逆序对数除了使用数据结构外,也可以在归并排序的基础上统计额外信息来求得。\\
假设我们现在要统计数列 A 中逆序对的个数。如图所示,我们可以将数列$A$平均分成两半得到数列$B$和数列 C于是数列 A 中的逆序对 ) , ( j i 必然是下面三种之一:\\ 假设我们现在要统计数列 A 中逆序对的个数。如图所示,我们可以将数列$A$平均分成两半得到数列$B$和数列$C$,于是,数列$A$中的逆序对$(i,j)$必然是下面三种之一:\\
(1)$i,j$都属于数列$B$的逆序对$(i,j)$\\ (1)$i,j$都属于数列$B$的逆序对$(i,j)$\\
(2)$i,j$都属于数列$C$的逆序对$(i,j)$\\ (2)$i,j$都属于数列$C$的逆序对$(i,j)$\\
(3)$i$属于数列$B$$j$属于数列$C$的逆序对$(i,j)$\\ (3)$i$属于数列$B$$j$属于数列$C$的逆序对$(i,j)$\\
@ -571,4 +571,23 @@ Manacher 模板题
\codeinput[\href{http://acm.hdu.edu.cn/showproblem.php?pid=1007}{HDU1007} - Quoit Design]{assets/day8/hdu1007.cpp} \codeinput[\href{http://acm.hdu.edu.cn/showproblem.php?pid=1007}{HDU1007} - Quoit Design]{assets/day8/hdu1007.cpp}
\subsection{树分治} 暂时跳过 \subsection{树分治} 暂时跳过
\subsection{cdq分治} 暂时跳过 \subsection{cdq分治} 暂时跳过
\section{数据结构 II}
\subsection{平衡树}
\subsubsection{前导知识}
\paragraph{二叉搜索树} 假定我们都知道什么是二叉搜索树。
\paragraph{二叉搜索树的旋转} 假定我们都知道如何左旋和右旋。
\paragraph{算法时间复杂度分析初步} 没有必要的知识。
\subsubsection{Splay}
\paragraph{简介} 一种通过Splay操作使\textbf{均摊}时间复杂度为$\log{n}$的二叉搜索树。
\paragraph{Splay操作} 将一个点移动到它上方的指定位置。
\subparagraph{节点$x$的父节点$y$是根节点}$x$通过左旋或右旋转到根。结束。
\subparagraph{节点$x$的父节点$y$不是根节点,$y$的父节点为$z$,且$x$$y$同时是各自父节点的左孩子或者同时是各自父节点的右孩子} 先将$y$转上去,再将$x$转上去。
\subparagraph{节点$x$的父节点$y$不是根节点,$y$的父节点为$z$,且$x$$y$一个是其父节点的左孩子而另一个是其父节点的右孩子}$x$转上去两次。
\paragraph{示例代码} 模板题
\codeinput[\href{http://www.lydsy.com/JudgeOnline/problem.php?id=3224}{BZOJ3224} - 普通平衡树]{assets/day10/Splay.cpp}
\subsubsection{Treap}
\paragraph{简介} 权值满足堆性质,\textbf{期望}时间复杂度为$\log{n}$的二叉搜索树。
\paragraph{做法} 插入之后维护一下堆性质,乱搞搞就好了,递归的方法写起来很容易,并且不易写错。删除的时候就把那个节点转到一条链上,然后删掉它。
\paragraph{示例代码} 模板题
\codeinput[\href{http://www.lydsy.com/JudgeOnline/problem.php?id=3224}{BZOJ3224} - 普通平衡树]{assets/day10/Treap.cpp}
\end{document} \end{document}
Loading…
Cancel
Save