zoukankan      html  css  js  c++  java
  • ☆ [ZJOI2006] 书架 「平衡树维护数列」

    题目类型:平衡树

    传送门:>Here<

    题意:要求维护一个数列,支持:将某个元素置顶或置底,交换某元素与其前驱或后继的位置,查询编号为(S)的元素的排名,查询排名第(k)的元素编号

    解题思路

    可以说是平衡树维护数列的入门题。当平衡树在维护数列时,关键字是在数列中的排名。因此中序遍历即为当前数列。注意在平衡树维护数列中,会涉及到两个编号。一个编号是这个节点在平衡树内的编号,一般外界是不会直接访问的。另一个是题目赋予的编号,代表这个位置数列上对应的值。外部编号即为一个附加值。当我们需要找到外部编号为(S)的元素,好像比较麻烦。此时,我们需要多开一个数组(pos),令(pos[idx[o]]=o),相当于是(idx)数组的逆运算。在知道一个外部编号时,能够迅速找到其所对应的节点编号。然后就可以对其进行直接操作了

    至于前驱后继交换,我们只需要交换这两个节点所对应的外部编号以及更新(pos),没有必要交换平衡树内的节点。

    Code

    /*By DennyQi 2018*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    using namespace std;
    typedef long long ll;
    const int MAXN = 80010;
    const int INF = 1061109567;
    inline int Max(const int a, const int b){ return (a > b) ? a : b; }
    inline int Min(const int a, const int b){ return (a < b) ? a : b; }
    inline int read(){
        int x = 0; int w = 1; register char c = getchar();
        for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
        if(c == '-') w = -1, c = getchar();
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
    }
    int N,M,S,T;
    char opt[10];
    int idx[MAXN],pos[MAXN];
    struct Splay{
    	int fa[MAXN],ch[MAXN][2],size[MAXN],num_node,rt;
    	inline void update(int x){
    		size[x] = 1;
    		if(ch[x][0]) size[x] += size[ch[x][0]];
    		if(ch[x][1]) size[x] += size[ch[x][1]];
    	}
    	inline bool rson(int f, int x){
    		return ch[f][1] == x;
    	}
    	inline void rotate(int x){
    		int f = fa[x], gf = fa[f];
    		bool p = rson(f, x), q = !p;
    		if(!gf) rt = x; else ch[gf][rson(gf,f)] = x;
    		fa[x] = gf;
    		ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
    		ch[x][q] = f, fa[f] = x;
    		update(f), update(x);
    	}
    	inline void splay(int x, int target){
    		int f,gf;
    		while(fa[x] != target){
    			f = fa[x], gf = fa[f];
    			if(gf == target){
    				rotate(x);
    				break;
    			}
    			if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f);
    			rotate(x);
    		}
    	}
    	inline void init(int id){
    		if(!rt){
    			rt = ++num_node;
    			idx[num_node] = id;
    			pos[id] = num_node;
    			size[num_node] = 1;
    			return;
    		}
    		int pre_rt = rt;
    		rt = ++num_node;
    		ch[rt][0] = pre_rt;
    		fa[pre_rt] = rt;
    		size[rt] = size[pre_rt] + 1;
    		idx[rt] = id;
    		pos[id] = rt;
    	}
    	inline void top(int s){
    		int o = pos[s];
    		splay(o, 0);
    		if(!ch[rt][0] && !ch[rt][1]) return;
    		int p = ch[rt][1];
    		if(!p){
    			ch[rt][1] = ch[rt][0];
    			ch[rt][0] = 0;
    			splay(ch[rt][1], 0);
    			return;
    		}
    		while(ch[p][0]) p = ch[p][0];
    		splay(p, rt);
    		ch[p][0] = ch[rt][0];
    		fa[ch[rt][0]] = p;
    		ch[rt][0] = 0;
    		update(p), update(rt);
    	}
    	inline void bottom(int s){
    		int o = pos[s];
    		splay(o, 0);
    		if(!ch[rt][0] && !ch[rt][1]) return;
    		int p = ch[rt][0];
    		if(!p){
    			ch[rt][0] = ch[rt][1];
    			ch[rt][1] = 0;
    			splay(ch[rt][0], 0);
    			return;
    		}
    		while(ch[p][1]) p = ch[p][1];
    		splay(p, rt);
    		ch[p][1] = ch[rt][1];
    		fa[ch[rt][1]] = p;
    		ch[rt][1] = 0;
    		update(p), update(rt);
    	}
    	inline int ask(int s){
    		int o = pos[s];
    		splay(o, 0);
    		return size[ch[rt][0]];
    	}
    	inline int query(int k){
    		int o = rt;
    		while(o){
    			if(size[ch[o][0]] >= k){
    				o = ch[o][0];
    			}
    			else if(size[ch[o][0]] + 1 < k){
    				k -= size[ch[o][0]] + 1;
    				o = ch[o][1];
    			}
    			else{
    				return idx[o];
    			}
    		}
    		return -1;
    	}
    	inline void insert(int S, int T){
    		if(T == 0) return;
    		splay(pos[S], 0);
    		if(T == -1){
    			int o = ch[rt][0];
    			while(ch[o][1]) o = ch[o][1];
    			splay(o, rt);
    			swap(idx[rt], idx[o]);
    			pos[idx[rt]] = rt, pos[idx[o]] = o;
    			update(o), update(rt);
    		}
    		if(T == 1){
    			int o = ch[rt][1];
    			while(ch[o][0]) o = ch[o][0];
    			splay(o, rt);
    			swap(idx[rt], idx[o]);
    			pos[idx[rt]] = rt, pos[idx[o]] = o;
    			update(o), update(rt);
    		}
    	}
    }qxz;
    int main(){
    	scanf("%d %d", &N, &M);
    	for(int i = 1; i <= N; ++i){
    		scanf("%d", &S);
    		qxz.init(S);
    	} 
    	while(M--){
    		scanf("%s %d", opt, &S);
    		if(opt[0] == 'T'){
    			qxz.top(S);
    		}
    		if(opt[0] == 'B'){
    			qxz.bottom(S);
    		}
    		if(opt[0] == 'A'){
    			printf("%d
    ", qxz.ask(S));
    		}
    		if(opt[0] == 'Q'){
    			printf("%d
    ", qxz.query(S));
    		}
    		if(opt[0] == 'I'){
    			scanf("%d", &T);
    			qxz.insert(S,T);
    		}
    	}
    }
    
  • 相关阅读:
    javascript 事件冒泡的补充
    不存在的数组元素
    Android应用程序线程消息循环模型分析
    Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析
    Linux下的压缩解压缩命令详解
    Android应用程序组件Content Provider简要介绍和学习计划
    Android应用程序组件Content Provider应用实例
    三层架构之初识庐山真面目
    Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
    Android应用程序消息处理机制(Looper、Handler)分析
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9654947.html
Copyright © 2011-2022 走看看