zoukankan      html  css  js  c++  java
  • bzoj1861: [Zjoi2006]Book 书架(平衡树)

    原题链接

    题目描述:小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

    输入格式:第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式:
    1. Top S——表示把编号为S的书房在最上面。
    2. Bottom S——表示把编号为S的书房在最下面。
    3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书;
    4. Ask S——询问编号为S的书的上面目前有多少本书。
    5. Query S——询问从上面数起的第S本书的编号。

    输出格式:对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

    输入样例
    10 10
    1 3 2 7 5 8 10 4 9 6
    Query 3
    Top 5
    Ask 6
    Bottom 3
    Ask 3
    Top 6
    Insert 4 -1
    Query 5
    Query 2
    Ask 2

    输出样例
    2
    9
    9
    7
    5
    3

    解析:算是平衡树中比较经典的题了,用splay和treap都可以解决。这里给出treap的做法。
       将每本书的位置作为权值插入treap中,记录val[x]为编号为x的书的位置。
       相比与treap的模板,要多对每一个节点记录一个ind,表示该点所表述的书的编号。
       那么对于Top操作,便是将原先书x的节点删除,再插入该节点(节点的权值要是所有数中最小的)。
       对于Bottom操作,就是将原先书x的节点删除,再插入该节点(节点的权值要是所有数中最大的)。
       对于Insert操作。若t是0,就直接continue;否则就将两个点都删除,再将两个点的信息交换后插入。
       对于Ask操作,就是输出val[x]的排名再-1。
       对于Query操作,就是输出排名为x的数的ind值。

    代码如下:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 80005;
    int n, m, root, val[maxn];
    int size[maxn << 1], lson[maxn << 1], rson[maxn << 1], c[maxn << 1], cnt, a[maxn << 1], pri[maxn << 1], ind[maxn << 1]; //数组要开两倍! 
    char s[10];
    
    int read(void) {
    	char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
    	if (c == '-') y = -1; else x = c - '0';
    	while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
    }
    
    int rand() { 
        static int seed = 2333;
        return seed = (int)((((seed ^ 998244353) + 19260817ll) * 19890604ll) % 1000000007);
    }
    
    void up(int k) {
    	size[k] = size[lson[k]] + size[rson[k]] + c[k];
    }
    
    void zig(int &k) {
    	int v = rson[k]; rson[k] = lson[v]; lson[v] = k;
    	size[v] = size[k]; up(k); k = v;
    }
    
    void zag(int &k) {
    	int v = lson[k]; lson[k] = rson[v]; rson[v] = k;
    	size[v] = size[k]; up(k); k = v;
    }
    
    void insert(int &k, int x, int id) { 
        if (k == 0) { 
          k = ++ cnt;  
          size[k] = c[k] = 1; a[k] = x; pri[k] = rand(); ind[k] = id;
          return;
        }
        size[k] ++;
        if (a[k] == x) c[k] ++;
        else if (x > a[k]) {
          insert(rson[k], x, id);
          if (pri[rson[k]] < pri[k]) zig(k);
        }
        else {
          insert(lson[k], x, id);
          if (pri[lson[k]] < pri[k]) zag(k);
        }
    }
    
    void del(int &k, int x) { 
        if (k == 0) return; 
        if (a[k] == x) {
          if (c[k] > 1) c[k] --, size[k] --;
          else {
            if (!lson[k] || !rson[k]) k = lson[k] + rson[k];
            else if (pri[lson[k]] < pri[rson[k]]) zag(k), del(k, x);
            else zig(k), del(k, x);
          }
        }
        else if (x > a[k]) size[k] --, del(rson[k], x);
        else size[k] --, del(lson[k], x);
    }
    
    int query_rank(int k, int x) { 
        if (k == 0) return 2e9;
        if (a[k] == x) return size[lson[k]] + 1;
        if (x > a[k]) return size[lson[k]] + c[k] + query_rank(rson[k], x);
        else return query_rank(lson[k], x);
    }
    
    int query_num(int k, int x) { 
        if (k == 0) return 2e9;
        if (x <= size[lson[k]]) return query_num(lson[k], x);
        x -= size[lson[k]];
        if (x <= c[k]) return ind[k]; //注意这里是ind! 
        x -= c[k]; 
        return query_num(rson[k], x);
    }
    
    int main() {
    	n = read(); m = read(); 
    	  for (int i = 1; i <= n; ++ i) {
    	  	int x = read();
    	  	val[x] = i;
    	  	insert(root, i, x);
    	  }
    	  for (int i = 1; i <= m; ++ i) {
    	  	scanf("%s", s + 1); 
    	  	if (s[1] == 'Q') {
    	  		int x = read();
    	  		printf("%d
    ", query_num(root, x));
    		  }
    		else if (s[1] == 'T') {
    		  int x = read();
    		  del(root, val[x]);
    		  insert(root, 1 - i, x);
    		  val[x] = 1 - i;
    		}
    		else if (s[1] == 'B') {
    		  int x = read();
    		  del(root, val[x]);
    		  insert(root, n + i, x);
    		  val[x] = n + i;
    		}
    		else if (s[1] == 'A') {
    		  int x = read();
    		  printf("%d
    ", query_rank(root, val[x]) - 1);
    		}
    		else if (s[1] == 'I') {
    		  int x = read(), y = read();
    		    if (y == 0) continue;
    		  int z = query_num(root, query_rank(root, val[x]) + y);
    		  del(root, val[x]);
    		  del(root, val[z]);
    		  insert(root, val[x], z);
    		  insert(root, val[z], x);
    		  swap(val[x], val[z]);
    		}
    	  }
    	return 0;
    } 
    
  • 相关阅读:
    LeetCode_1025.除数博弈
    LeetCode_102.二叉树的层序遍历
    Oracle报错:不是GROUP BY 表达式
    Oracle报错:不是单组分组函数
    不允许保存更改。您所做的更改要求删除并重新创建以下表。您对无法重新创建的表进行了更改或启用了“阻止保存要求重新创建表的更改”选项
    分页存储过程
    线程间操作无效: 从不是创建控件“labMessage”的线程访问它。
    C#连接oracle 数据库查询时输入中文查询不出来,用plsql就可以
    select ,update 加锁
    错误代码: 0x800700b7 配置错误:定义了重复的“system.web.extensions/scripting/scriptResourceHandler”节
  • 原文地址:https://www.cnblogs.com/Gaxc/p/10127422.html
Copyright © 2011-2022 走看看