• 【模板】普通平衡树


    题面

    题解

    过年啦!!!

    在这红红火火的日子里,肯定要写(color{red}{mathrm{Red}};color{black}{mathrm{Black}};tree)来愉悦身心啊

    然鹅出现了一些小尴尬

    虽然代码行数跟(mathrm{s(p)lay})没法比肯定是大括号太占地方了

    但是:

    指针版的(mathrm{s(p)lay})https://www.luogu.org/recordnew/show/8772600

    (color{red}{mathrm{Red}};color{black}{mathrm{Black}};tree)https://www.luogu.org/recordnew/show/16079271

    代码长度比较起来,红黑树胜!!!

    ha???

    速度当然也是吊着打啦

    从此红黑树走进了每个OIer的电脑

    代码

    我这能算突破红黑树代码长度极限了吗(mathrm{QwQ})

    #include<cstdio>
    #include<cstring>
    #include<climits>
    #define RG register
    
    inline int read()
    {
    	int data = 0, w = 1;
    	char ch = getchar();
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(1e6 + 10);
    int son[2][maxn], fa[maxn], size[maxn], cur;
    int cnt[maxn], col[maxn], val[maxn], root;
    inline void newNode(int k, int c, int f)
    {
    	int x = ++cur;
    	fa[x] = f, size[x] = cnt[x] = 1;
    	val[x] = k, col[x] = c;
    }
    
    inline void update(int x) { size[x] = size[son[0][x]] + cnt[x] + size[son[1][x]]; }
    inline void rotate(int x, int r)
    {
    	int y = son[!r][x]; son[!r][x] = son[r][y];
    	if(son[r][y]) fa[son[r][y]] = x;
    	fa[y] = fa[x]; if(!fa[x]) root = y;
    	else son[x == son[1][fa[x]]][fa[x]] = y;
    	son[r][y] = x, fa[x] = y, size[y] = size[x];
    	update(x);
    }
    
    inline void transplant(int to, int from)
    {
    	fa[from] = fa[to]; if(!fa[to]) root = from;
    	else son[to == son[1][fa[to]]][fa[to]] = from;
    }
    
    int findMin(int x) { while(son[0][x]) x = son[0][x]; return x; }
    void insertFixUp(int z)
    {
    	while(col[fa[z]])
    	{
    		int f = fa[z], g = fa[f], l = f == son[0][g], y = son[l][g];
    		if(col[y]) col[y] = col[f] = 0, col[z = g] = 1;
    		else
    		{
    			if(z == son[l][f]) z = f, rotate(z, !l);
    			col[fa[z]] = 0, col[fa[fa[z]]] = 1; rotate(g, l);
    		}
    	}
    	col[root] = 0;
    }
    
    void insert(int k)
    {
    	int x = root, y = 0;
    	while(x)
    	{
    		++size[y = x]; if(val[x] == k) return (void) (++cnt[x]);
    		x = son[val[x] < k][x];
    	}
    	newNode(k, 1, y);
    	if(!y) root = cur; else son[val[y] < k][y] = cur;
    	insertFixUp(cur);
    }
    
    void delFixUp(int x)
    {
    	while(x != root && (!col[x]))
    	{
    		int l = x == son[0][fa[x]], f = fa[x], w = son[l][f];
    		if(col[w])
    		{
    			col[f] = 1, col[w] = 0;
    			rotate(f, !l); w = son[l][f];
    		}
    		if((!col[son[0][w]]) && (!col[son[1][w]])) col[w] = 0, x = fa[x];
    		else
    		{
    			if(!col[son[l][w]])
    				col[w] = 1, col[son[!l][w]] = 0,
    				rotate(w, l), w = son[l][f];
    			col[w] = col[f], col[f] = 0; col[son[l][w]] = 0;
    			rotate(fa[w], !l); x = root;
    		}
    	}
    	col[x] = 0;
    }
    
    void erase(int k)
    {
    	int z = root, w = 0;
    	while(z)
    	{
    		--size[w = z]; if(k == val[z]) break;
    		z = son[val[z] < k][z];
    	}
    	if(z)
    	{
    		if(cnt[z] > 1) return (void) (--cnt[z]);
    		int y = z, x, oldc = col[y];
    		if(!son[0][z]) x = son[1][z], transplant(z, son[1][z]);
    		else if(!son[1][z]) x = son[0][z], transplant(z, son[0][z]);
    		else
    		{
    			y = findMin(son[1][z]); oldc = col[y], x = son[1][y];
    			if(fa[y] == z) fa[x] = y;
    			else
    			{
    				int tmpy = y;
    				while(tmpy != z) size[tmpy] -= cnt[y], tmpy = fa[tmpy];
    				transplant(y, son[1][y]); son[1][y] = son[1][z];
    				fa[son[1][y]] = y;
    			}
    			transplant(z, y); son[0][y] = son[0][z];
    			fa[son[0][y]] = y, col[y] = col[z]; update(y);
    		}
    		if(!oldc) delFixUp(x);
    	}
    	else while(w) ++size[w], w = fa[w];
    }
    
    inline int cmp(int x, int k) { return (val[x] < k) ? 0 : (val[x] ^ k ? 1 : -1); }
    int suc(int k, int b)
    {
    	int x = root, p = 0;
    	while(x) if(cmp(x, k) == b) p = x, x = son[!b][x];
    	else x = son[b][x];
    	return val[p];
    }
    
    int k_th(int k)
    {
    	int x = root;
    	while(x)
    	{
    		int l = son[0][x], r = son[1][x];
    		if(size[l] + 1 <= k && size[l] + cnt[x] >= k) return val[x];
    		else if(size[l] + cnt[x] < k) k -= size[l] + cnt[x], x = r; else x = l;
    	}
    	return INT_MAX;
    }
    
    inline int rank(int r)
    {
    	int x = root, ret = 0;
    	while(x)
    	{
    		if(val[x] < r) ret += size[son[0][x]] + cnt[x], x = son[1][x];
    		else x = son[0][x];
    	}
    	return ret + 1;
    }
    
    int main()
    {
    	int n = read();
    	while(n--)
    	{
    		int opt = read(), x = read();
    		switch(opt)
    		{
    			case 1: insert(x); break;
    			case 2: erase(x); break;
    			case 3: printf("%d
    ", rank(x)); break;
    			case 4: printf("%d
    ", k_th(x)); break;
    			case 5: case 6: printf("%d
    ", suc(x, opt - 5)); break;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    从killchain的角度检测APT攻击
    挖洞实战之信息泄露与前端加密
    浅析MySQL恶意服务器读取文件原理
    MySQL决胜秋招Section
    MySQL窗口函数
    MySQL集合运算
    Chrome 插件神仙网站推荐 !直接就能下,2022年最新!
    Clickhouse分桶聚合后填充零值问题
    深入理解C#笔记
    JavaCV音视频开发宝典:视频转码和转封装有什么区别?使用rtsp拉流转推到rtmp案例来讲一下转码和转封装实现的区别
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10353748.html
Copyright © 2020-2023  润新知