平衡树巩固——part1.简单

    最近预计做一下各种平衡树的题,这是第一部分,就是一类简单的各种操作,由于实在是太简单了,各种数据结构都可以胜任,我就用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进发了,去年的时候搞了一下,现在看来发现丑得无可比拟,一定要重写一个比较漂亮的单旋版本!

posted @ 2011-10-29 11:33  Neroysq  阅读(358)  评论(0编辑  收藏  举报