最近预计做一下各种平衡树的题,这是第一部分,就是一类简单的各种操作,由于实在是太简单了,各种数据结构都可以胜任,我就用treap和sbt分别做了一遍平衡树的三大水题,于是这两种数据结构就比较熟练了。
treap就是普通的二叉排序树多满足了一个堆的性质,相当好写,贴一贴三道题的代码:
1.hnoi2002 turnover(无敌大水题)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int nmax = 32767;
int ans, n, tot, root;
struct typetreapnode
{
int chi[2], val, fix;
}tap[nmax + 18];
int min(int a, int b)
{
return a > b ? b : a;
}
void rotate_treap(int m, int &p)//0 left 1 right
{
int b = tap[p].chi[m ^ 1];
tap[p].chi[m ^ 1] = tap[b].chi[m];
tap[b].chi[m] = p;
if (p == root) root = b;
p = b;
}
void insert_treap(int x, int &p)
{
if (!p)
{
p = ++tot;
tap[tot].val = x;
tap[tot].fix = rand();
}
else
{
int m = (tap[p].val <= x);
insert_treap(x, tap[p].chi[m]);
if (tap[tap[p].chi[m]].fix < tap[p].fix)
rotate_treap(m ^ 1, p);
}
}
void find_treap(int m, int val, int p, int &opt)
{
if (!p)
return;
bool k = (tap[p].val >= val);
if (!(k ^ m))
find_treap(m, val, tap[p].chi[m ^ 1], opt = p);
else
find_treap(m, val, tap[p].chi[m], opt);
}
int main()
{
srand((unsigned) time(NULL));
scanf("%d%d", &n, &ans);
insert_treap(ans, root);
root = 1;
for (int i = 2, tmp, pre, suc; i <= n; ++i)
{
scanf("%d", &tmp);
pre = suc = 0;
if (i == n)
i = i + i - i;
find_treap(0, tmp, root, pre);
find_treap(1, tmp, root, suc);
ans += min(pre ? tmp - tap[pre].val : 99999999, suc ? tap[suc].val - tmp : 99999999);
insert_treap(tmp, root);
}
printf("%d", ans);
return 0;
}
2.hnoi 2004 pet
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int nmax = 80000, mo = 1000000;
struct typetreapnode
{
int chi[2], fix, val;
}tap[nmax + 18];
int n, now, rnt, ans, root, tot;
void rotate(int &p, int m)
{
int b = tap[p].chi[m ^ 1];
tap[p].chi[m ^ 1] = tap[b].chi[m];
tap[b].chi[m] = p;
p = b;
}
void insert_treap(int &p, int x)
{
if (!p)
{
tap[p = ++tot].val = x;
tap[p].fix = rand();
}
else
{
int m = (tap[p].val < x);
insert_treap(tap[p].chi[m], x);
if (tap[p].fix > tap[tap[p].chi[m]].fix)
rotate(p, m ^ 1);
}
}
void findround_treap(int p, int x, int m, int &opt)
{
if (!p) return;
int k = (tap[p].val >= x);
if (!(k ^ m))
findround_treap(tap[p].chi[m ^ 1], x, m, opt = p);
else
findround_treap(tap[p].chi[m], x, m, opt);
}
void delete_treap(int &p, int x)
{
if (x == tap[p].val)
{
if (!tap[p].chi[0] || !tap[p].chi[1])
p = tap[p].chi[!tap[p].chi[0]];
else
{
int m = tap[tap[p].chi[0]].fix < tap[tap[p].chi[1]].fix;
rotate(p, m ^ 1);
delete_treap(tap[p].chi[m ^ 1], x);
}
}
else
delete_treap(tap[p].chi[tap[p].val < x], x);
}
int better(int a, int b, int x)
{
if (!a) return b;
if (!b) return a;
return abs(tap[a].val - x) > abs(tap[b].val - x) ? b : a;
}
int main()
{
scanf("%d", &n);
srand((unsigned)time(NULL));
for (int i = 1, a, b, pre, suc; i <= n; ++i)
{
scanf("%d%d", &a, &b);
if (!rnt || a == now) insert_treap(root, b), now = a, ++rnt;
else
{
pre = suc = 0;
findround_treap(root, b, 0, pre);
findround_treap(root, b, 1, suc);
pre = better(pre, suc, b);
ans = (ans + abs(b - tap[pre].val)) % mo;
delete_treap(root, tap[pre].val);
--rnt;
}
}
printf("%d", ans);
return 0;
}
3.noi2004 cashier
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int nmax = 100000;
struct typetreapnode
{
int chi[2], val, fix, sze;
}tap[nmax + 18];
int n, min, ans, del, root, tot, tmp;
char c;
void rotate_treap(int &p, int m) //0 left 1 right
{
int b = tap[p].chi[m ^ 1];
tap[p].chi[m ^ 1] = tap[b].chi[m];
tap[b].chi[m] = p;
tap[b].sze = tap[p].sze;
tap[p].sze = tap[tap[p].chi[0]].sze + tap[tap[p].chi[1]].sze + 1;
p = b;
}
void insert_treap(int &p, int x)
{
if (!p)
{
tap[p = ++tot].val = x;
tap[tot].sze = 1;
tap[tot].fix = rand();
}
else
{
int m = (tap[p].val < x);
++tap[p].sze;
insert_treap(tap[p].chi[m], x);
if (tap[tap[p].chi[m]].fix < tap[p].fix)
rotate_treap(p, m ^ 1);
}
}
void deletegroup_treap(int &p, int x)
{
if (!p) return;
if (tap[p].val < x)
{
tap[p].sze = 0;
deletegroup_treap(p = tap[p].chi[1], x);
}
else
{
deletegroup_treap(tap[p].chi[0], x);
tap[p].sze = tap[tap[p].chi[0]].sze + tap[tap[p].chi[1]].sze + 1;
}
}
void findbyrank_treap(int p, int rank, int &pos)
{
if ((tmp = tap[tap[p].chi[0]].sze + 1) == rank) return (void) (pos = p);
if (tmp < rank)
findbyrank_treap(tap[p].chi[1], rank - tmp, pos);
else
findbyrank_treap(tap[p].chi[0], rank, pos);
}
int main()
{
srand((unsigned) time(NULL));
scanf("%d%d\n", &n, &min);
for (int i = 1, k; i <= n; ++i)
{
scanf("%c %d\n", &c, &k);
if (c == 'I')
if (k >= min)
insert_treap(root, k - del), ++ans;
else
ans = ans;
else
if (c == 'A')
del += k;//lowbound = min + del
else
if (c == 'S')
{
del -= k;
deletegroup_treap(root, min - del);
}
else
if (k <= tap[root].sze)
{
int pos;
findbyrank_treap(root, tap[root].sze - k + 1, pos);
printf("%d\n", tap[pos].val + del);
}
else
printf("-1\n");
}
printf("%d", ans - tap[root].sze);
return 0;
}
sbt和treap相当像,只不过把维护堆性质的操作换成了maintain,这个过程其实不是很好懂,每次都要推好久,不过代码只有8行,果断背啊!
1.turnover
#include <stdio.h>
#include <stdlib.h>
const int nmax = 32767;
int n, ans, root, tot, pre, suc;
struct typesbt
{
int sze, val, chi[2];
}sbt[nmax + 18];
void rotate(int &p, int m) //l 0 r 1
{
int b = sbt[p].chi[m ^ 1];
sbt[p].chi[m ^ 1] = sbt[b].chi[m];
sbt[b].chi[m] = p;
sbt[b].sze = sbt[p].sze;
sbt[p].sze = sbt[sbt[p].chi[0]].sze + sbt[sbt[p].chi[1]].sze + 1;
p = b;
}
void maintain(int &p, int m)
{
if (sbt[sbt[sbt[p].chi[m]].chi[m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(p, !m);
else if (sbt[sbt[sbt[p].chi[m]].chi[!m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(sbt[p].chi[m], m), rotate(p, !m);
else
return;
maintain(sbt[p].chi[0], 0);
maintain(sbt[p].chi[1], 1);
maintain(p, 0);
maintain(p, 1);
}
void insert_sbt(int &p, int x)
{
if (!p)
{
sbt[p = ++tot].sze = 1;
sbt[p].val = x;
}
else
{
++sbt[p].sze;
insert_sbt(sbt[p].chi[sbt[p].val <= x], x);
maintain(p, x >= sbt[p].val);
}
}
void searchround_sbt(int p, int x, int m, int &opt)
{
if (!p) return ;
int k = (sbt[p].val >= x);
if (!(m ^ k))
searchround_sbt(sbt[p].chi[m ^ 1], x, m, opt = p);
else
searchround_sbt(sbt[p].chi[m], x, m, opt);
}
int getmin(int a, int b, int p)
{
if (!a) return abs(p - sbt[b].val);
if (!b) return abs(p - sbt[a].val);
return ((a = abs(p - sbt[a].val)) > (b = abs(p - sbt[b].val))) ? b : a;
}
int main()
{
scanf("%d", &n);
scanf("%d", &ans);
insert_sbt(root, ans);
for (int i = 2, tmp; i <= n; ++i)
{
scanf("%d", &tmp);
pre = suc = 0;
searchround_sbt(root, tmp, 0, pre);
searchround_sbt(root, tmp, 1, suc);
ans += getmin(pre, suc, tmp);
insert_sbt(root, tmp);
}
printf("%d", ans);
return 0;
}
2.pet
#include <stdio.h>
#include <stdlib.h>
const int nmax = 80000, mo = 1000000;
struct typesbt
{
int sze, val, chi[2];
}sbt[nmax + 18];
int n, now, rnt, tot, ans;
int root, pre, suc;
void rotate(int &p, int m)
{
int b = sbt[p].chi[!m];
sbt[p].chi[!m] = sbt[b].chi[m];
sbt[b].chi[m] = p;
sbt[b].sze = sbt[p].sze;
sbt[p].sze = sbt[sbt[p].chi[0]].sze + sbt[sbt[p].chi[1]].sze + 1;
p = b;
}
void maintain(int &p, int m)
{
if (sbt[sbt[sbt[p].chi[m]].chi[m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(p, !m);
else
if (sbt[sbt[sbt[p].chi[m]].chi[!m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(sbt[p].chi[m], m), rotate(p, !m);
else
return;
maintain(sbt[p].chi[0], 0);
maintain(sbt[p].chi[1], 1);
maintain(p, 0);
maintain(p, 1);
}
void insert_sbt(int &p, int x)
{
if (!p)
{
sbt[p = ++tot].sze = 1;
sbt[tot].val = x;
}
else
{
++sbt[p].sze;
insert_sbt(sbt[p].chi[sbt[p].val <= x], x);
maintain(p, sbt[p].val <= x);
}
}
void searchround_sbt(int p, int m, int x, int &opt)
{
if (!p) return;
int k = (sbt[p].val >= x);
if (!(m ^ k))
searchround_sbt(sbt[p].chi[!m], m, x, opt = p);
else
searchround_sbt(sbt[p].chi[m], m, x, opt);
}
int deletenode_sbt(int &p, int x)
{
--sbt[p].sze;
if (x == sbt[p].val || !sbt[p].chi[x > sbt[p].val])
{
int rnt = sbt[p].val;
if (!sbt[p].chi[0] || !sbt[p].chi[1])
p = sbt[p].chi[!sbt[p].chi[0]];
else
sbt[p].val = deletenode_sbt(sbt[p].chi[0], x + 1);
return rnt;
}
else
return deletenode_sbt(sbt[p].chi[x > sbt[p].val], x);
}
int chkmin(int &a, int b, int c)
{
if (!a || abs(sbt[a].val - c) > abs(sbt[b].val - c)) a = b;
return abs(sbt[a].val - c);
}
int main()
{
scanf("%d", &n);
for (int i = 1, a, b; i <= n; ++i)
{
scanf("%d%d", &a, &b);
if (!rnt || now == a) insert_sbt(root, b), now = a, ++rnt;
else
{
suc = pre = 0;
searchround_sbt(root, 0, b, pre);
searchround_sbt(root, 1, b, suc);
ans = (ans + chkmin(pre, suc, b)) % mo;
--rnt;
deletenode_sbt(root, sbt[pre].val);
}
}
printf("%d", ans);
return 0;
}
3.cashier
#include <stdio.h>
const int nmax = 100000;
struct typesbt
{
int sze, chi[2], val;
}sbt[nmax + 18];
int n, ans, del, min, tot, num, root;
char c;
void rotate(int &p, int m)
{
int b = sbt[p].chi[!m];
sbt[p].chi[!m] = sbt[b].chi[m];
sbt[b].chi[m] = p;
sbt[b].sze = sbt[p].sze;
sbt[p].sze = sbt[sbt[p].chi[0]].sze + sbt[sbt[p].chi[1]].sze + 1;
p = b;
}
void maintain(int &p, int m)
{
if (sbt[sbt[sbt[p].chi[m]].chi[m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(p, !m);
else
if (sbt[sbt[sbt[p].chi[m]].chi[!m]].sze > sbt[sbt[p].chi[!m]].sze)
rotate(sbt[p].chi[m], m), rotate(p, !m);
else
return;
maintain(sbt[p].chi[0], 0);
maintain(sbt[p].chi[1], 1);
maintain(p, 0);
maintain(p, 1);
}
void insert_sbt(int &p, int x)
{
if (!p)
{
sbt[p = ++tot].sze = 1;
sbt[p].val = x;
}
else
{
++sbt[p].sze;
insert_sbt(sbt[p].chi[sbt[p].val <= x], x);
maintain(p, sbt[p].val <= x);
}
}
void deletegroup_sbt(int &p, int x)
{
if (!p) return;
if (sbt[p].val < x)
{
sbt[p].sze = 0;
deletegroup_sbt(p = sbt[p].chi[1], x);
}
else
{
deletegroup_sbt(sbt[p].chi[0], x);
sbt[p].sze = sbt[sbt[p].chi[0]].sze + sbt[sbt[p].chi[1]].sze + 1;
}
}
int getbyrank_sbt(int p, int k)
{
int tmp = sbt[sbt[p].chi[0]].sze + 1;
if (tmp == k) return p;
if (tmp < k)
return getbyrank_sbt(sbt[p].chi[1], k - tmp);
else
return getbyrank_sbt(sbt[p].chi[0], k);
}
int main()
{
scanf("%d%d", &n, &min);
for (int i = 1, tmp; i <= n; ++i)
{
scanf("\n%c %d", &c, &tmp);
if (c == 'I')
if (tmp >= min)
insert_sbt(root, tmp - del), ++num;
else
;
else
if (c == 'A')
del += tmp;
else
if (c == 'S')
{
del -= tmp;
deletegroup_sbt(root, min - del);
}
else
printf("%d\n", tmp <= sbt[root].sze ? sbt[getbyrank_sbt(root, sbt[root].sze - tmp + 1)].val + del : -1);
}
printf("%d", num - sbt[root].sze);
return 0;
}
总之,上面这些水题多多少少耗了我两个晚自习,下面就要向序列之神,维护之神——splay进发了,去年的时候搞了一下,现在看来发现丑得无可比拟,一定要重写一个比较漂亮的单旋版本!