[NOI2004]郁闷的出纳员
本题涉及到的操作有:单点插入,区间更新,删除比x小的数,询问第k大的数。
可以用splay维护一个有序的序列。
先给splay分配一个虚拟结点,
虚拟结点的v等于-INF,这样保证了虚拟结点的左儿子始终为null。。
插入操作:
计算比x小的数的个数k,对原序列split。。。
有序插入,使得序列始终保持 -oo 10 20 30 40 这样子。
--记得pushdown(), 要把所有值算出来,才能确定大小。下同。
void add(int x) {//从小到大插入x cnt++; Node *p = ss.root; int k = 0; while ( p != null ) { p->pushdown(); if(p->v > x) p = p->ch[0]; else { k += p->ch[0]->s + 1; p = p->ch[1]; } } Node *left, *right; split(ss.root, k, left, right); Node *mid = new Node(); mid->ch[0] = mid->ch[1] = null; mid->s = 1;//很关键 mid->v = x; mid->lazy = 0; ss.root = merge(merge(left, mid), right); }
删除比x小的数:
同样是计算比x小的个数k,然后要特殊判断一下k是否为1;
把虚拟结点单提出来,那么要删除的结点一共有k-1个。。
void del(int x) {//删除比x小的数 int k = 0; Node *p = ss.root; while ( p != null ) { p->pushdown(); if(p->v >= x) p = p->ch[0]; else { k += p->ch[0]->s + 1; p = p->ch[1]; } } if(k == 1) return; Node *left, *mid, *right, *o; split(ss.root, 1, left, o); split(o, k-1, mid, right); ss.root = merge(left, right); cnt -= k-1; leave += k-1; }
区间更新:
把虚拟结点提出来,对剩下的那些有序序列打延迟标记。
void updata(int c) { Node *left, *right; split(ss.root, 1, left, right); right->v += c; right->lazy += c; ss.root = merge(left, right); }
询问第k大数:
要找第k大数,只需要找包括虚拟结点在内的第cnt-k+1个数。
int query(int k) {//询问第k大的数 if(cnt-1 < k) return -1; Node *left, *mid, *right, *o; k = cnt-k+1; //printf ( "k=%d\n", k ); split(ss.root, k, left, right); //printf("left:");debug(left);puts(""); ss.root = merge(left, right); return left->v; }
数组法:
void add(int x) { ++cnt; int k = 0, p = root; while ( p ) { push_down(p); if ( val[p] > x ) p = ch[p][0]; else { k += sz[ch[p][0]] + 1; p = ch[p][1]; } } RotateTo(k-1, 0); RotateTo(k, root); int key; NewNode(key, x); ch[ch[root][1]][0] = key; pre[key] = ch[root][1]; push_up(ch[root][1]); push_up(root); } void del(int x) { int k = 0, p = root; while ( p ) { push_down(p); if ( val[p] >= x ) p = ch[p][0]; else { k += sz[ch[p][0]] + 1; p = ch[p][1]; } } RotateTo(0, 0); RotateTo(k, root); int key = ch[ch[root][1]][0]; ch[ch[root][1]][0] = 0; push_up(root); cnt -= sz[key]; leave += sz[key]; } void updata(int c) { RotateTo(0, 0); RotateTo(cnt+1, root); int key = ch[ch[root][1]][0]; val[key] += c; lazy[key] += c; push_up(root); } int query(int k) {//询问第k大的数 if ( k > cnt ) return -1; k = cnt - k + 1; RotateTo(k-1, 0); RotateTo(k+1, root); int key = ch[ch[root][1]][0]; return val[key]; }