bzoj1503 Splay 维护名次数,支持删除

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1503

题解:

维护一颗Splay和一个外部变量,树中每个节点表示一个人,节点权值a + 外部变量delta = 该员工工资。

细节看代码。

注意:一进来工资就低于最低工资的人不能算是“离开公司”的人。

  1 #include <cstdio>
  2 #define fprintf(...)
  3 #define maxn 100100
  4
  5 struct Splay {
  6     int key[maxn], pre[maxn], son[maxn][2], siz[maxn], ntot, root;
  7     int trash[maxn], rtot;
  8
  9     Splay():ntot(0),root(0),rtot(0){}
 10     void update( int nd ) {
 11         siz[nd] = siz[son[nd][0]] + siz[son[nd][1]] + 1;
 12     }
 13     void rotate( int nd, int d ) {
 14         int p = pre[nd];
 15         int s = son[nd][!d];
 16         int ss = son[s][d];
 17
 18         if( p ) son[p][ nd==son[p][1] ] = s;
 19         else root = s;
 20         son[nd][!d] = ss;
 21         son[s][d] = nd;
 22
 23         if( ss ) pre[ss] = nd;
 24         pre[nd] = s;
 25         pre[s] = p;
 26
 27         update( nd );
 28         update( s );
 29     }
 30     void splay( int nd, int top=0 ) {
 31         while( pre[nd]!=top ) {
 32             int p = pre[nd];
 33             int nl = nd==son[p][0];
 34             if( pre[p]==top ) {
 35                 rotate( p, nl );
 36             } else {
 37                 int pp = pre[p];
 38                 int pl = p==son[pp][0];
 39                 if( nl==pl ) {
 40                     rotate( pp, pl );
 41                     rotate( p, nl );
 42                 } else {
 43                     rotate( p, nl );
 44                     rotate( pp, pl );
 45                 }
 46             }
 47         }
 48     }
 49     int newnode( int k, int p ) {
 50         int nd;
 51         if( rtot ) nd = trash[rtot--];
 52         else nd = ++ntot;
 53         key[nd] = k;
 54         pre[nd] = p;
 55         son[nd][0] = son[nd][1] = 0;
 56         siz[nd] = 1;
 57         return nd;
 58     }
 59     void insert( int k ) {
 60         fprintf( stderr, "insert(%d)\n", k );
 61         if( !root ) {
 62             root = newnode( k, 0 );
 63             return;
 64         }
 65         int nd = root;
 66         while( son[nd][ k<key[nd] ] )
 67             nd = son[nd][ k<key[nd] ];
 68         son[nd][ k<key[nd] ] = newnode( k, nd );
 69         update( nd );
 70         splay( nd, 0 );
 71     }
 72     void erase_subtree( int nd ) {
 73         fprintf( stderr, "erase_subtree(%d)\n", nd );
 74         if( !nd ) return;
 75         erase_subtree( son[nd][0] );
 76         erase_subtree( son[nd][1] );
 77         trash[++rtot] = nd;
 78     }
 79     void erase( int k ) {
 80         fprintf( stderr, "erase(%d)\n", k );
 81         int nd = root;
 82         int active = nd;
 83         while( nd ) {
 84             if( key[nd]<=k ) {
 85                 int p = pre[nd];
 86                 int ls= son[nd][0];
 87
 88                 if( p ) son[p][ nd==son[p][1] ] = son[nd][0];
 89                 else root = son[nd][0];
 90                 pre[son[nd][0]] = p;
 91
 92                 pre[nd] = 0;
 93                 son[nd][0] = 0;
 94
 95                 erase_subtree( nd );
 96
 97                 if( p ) update( p );
 98                 nd = ls;
 99             } else {
100                 active = nd;
101                 nd = son[nd][1];
102             }
103         }
104         splay(active);
105     }
106     int nth( int n ) {
107         fprintf( stderr, "nth(%d)\n", n );
108         int nd = root;
109         while(1) {
110             int ls = siz[son[nd][0]];
111             if( n<=ls ) {
112                 nd=son[nd][0];
113             } else if( n>=ls+2 ) {
114                 nd=son[nd][1];
115                 n -= ls+1;
116             } else
117                 break;
118         }
119         splay( nd );
120         return key[nd];
121     }
122     void print( int nd ) {
123         if(!nd) return;
124         print( son[nd][0] );
125         fprintf( stderr, "%d %d %d %d %d\n", nd, pre[nd], son[nd][0], son[nd][1],
126                 key[nd] );
127         print( son[nd][1] );
128     }
129 };
130
131 Splay T;
132 int n, delta, limit, cnt;
133
134 int main() {
135     //freopen( "input", "r", stdin );
136     scanf( "%d%d", &n, &limit );
137     delta = 0;
138     cnt = 0;
139     while(n--) {
140         char ch[2];
141         int k;
142         scanf( "%s%d", ch, &k );
143         switch(ch[0]) {
144             case ‘I‘:
145                 if( k<limit ) break;
146                 cnt++;
147                 k -= delta;
148                 T.insert( k );
149                 break;
150             case ‘A‘:
151                 delta += k;
152                 break;
153             case ‘S‘:
154                 delta -= k;
155                 T.erase( limit-delta-1 );
156                 break;
157             case ‘F‘:
158                 if( !(1<=k && k<=T.siz[T.root]) ) printf( "-1\n" );
159                 else printf( "%d\n", T.nth(k)+delta );
160                 break;
161         }
162         fprintf( stderr, "delta=%d\n", delta );
163         //T.print( T.root );
164         fprintf( stderr, "\n" );
165     }
166     printf( "%d\n", cnt-T.siz[T.root] );
167 }

时间: 2024-12-19 03:37:04

bzoj1503 Splay 维护名次数,支持删除的相关文章

BZOJ 3786 星系探索 Splay维护树的入栈出栈序

题目大意:给出一棵树,要求有以下这些操作:1.求出一个节点到根的点权和.2.将一个节点的父亲改变.3.将一个子树中的每一个节点都加上一个权值. 思路:LCT就不用想了,因为有子树操作.然后就是一个很神奇的东西了,就是Splay维护树的入栈出栈序.这个玩应是做了这个题之后才知道的.但是感觉真的很dio. 首先,我们先按照题意,将树建出来.然后从根开始深搜,这样一个点进入DFS函数和出DFS函数的时候就会有两个时间点,就是入栈的时间和出栈的时间.然后利用Splay维护一个序列,就是入栈出栈的顺序.在

支持删除任意元素以及一些其他基本操作的堆

一个黑科技,不知道是谁发明的(好像也有些年代了?) 其实这个黑科技的本质就是一个大根堆,不同的是 它支持删除堆内任意元素,同时也支持堆的基本操作 code 代码如下: struct Heap{ priority_queue<int> q1,q2; inline void push(int x){q1.push(x);} inline void erase(int x){q2.push(x);} inline void pop(){for(;q2.size()&&q1.top()

bzoj 2300 动态维护上凸壳(不支持删除)

新技能GET. 用set保存点,然后只需要找前趋和后继就可以动态维护了. 1 /************************************************************** 2 Problem: 2300 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:556 ms 7 Memory:4824 kb 8 ************************************************

bzoj3173 Splay 维护前缀中的最大值

大致题意: 有一个空序列,依次插入1~N到该序列中,每次制定插入的位置,每次插入完成返回当前序列的LIS的长度. 题解: 设dp[i]表示 前缀1~i的最长上升子序列的长度. 因为是按照递增顺序插入的,所以dp[i] = max{ dp[j] | j<i },答案 ans=max{ dp[i] | i in [1,len] } 因为要支持动态插入,所以要用BST来做,每个节点代表一个位置(即树的中序遍历就是该序列),每个节点维护dp[i]和 dpmax[i] = max{ dp[i] | i i

BZOJ 2329 HNOI 2011 括号修复 Splay维护最大连续子段和

题目大意:给出一个括号序列,问一段区间最少需要修改多少括号使得这一段括号变成一段完整的括号序列. 思路:题解见http://ydcydcy1.blog.163.com/blog/static/2160890402013116111134791/ OTZ ydc 维护起来稍微有些麻烦啊.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #d

[XSY 1019] 小A学树论 Splay维护入栈出栈序

题意 给定一棵 n 个节点的树. 这棵树以 1 为根, 每个点有点权. 在树上支持三种操作: ① 查询以 x 为根的子树的点权之和; ② 将以 x 为根的子树中的每个点的点权增加 w ; ③ 将 以 x 为根的子树转移到 y 的直接后继. $n \le 100000$ . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #includ

UVa 11987 Almost Union-Find(支持删除操作的并查集)

传送门 Description I hope you know the beautiful Union-Find structure. In this problem, you’re to implement something similar, but not identical. The data structure you need to write is also a collection of disjoint sets, supporting 3 operations: 1 p q

sql2000中更换机器名后无法删除作业

最近重装公司数据库服务器,发现还原数据库后,作业不能删除及添加的作业不能正常运行.经网上查找资料后,采用如下方法处理后正常. 在msdb表中修改字段originating_server内容为新机器名后,便可删除作业 在安全性登陆中删除原有机器名的用户,新建新机器名的管理员用户 新建作业,便可正常运行.

mysql 每秒钟查询次数、插入次数、删除次数、更新次数的统计

-show global status where Variable_name in('com_select','com_insert','com_delete','com_update'); 查询出当前四种操作的总次数 x1 y1 z1 w1 --select sleep(60) 延时60秒 --show global status where Variable_name in('com_select','com_insert','com_delete','com_update'); 一分钟后