【洛谷 P1486】 [NOI2004]郁悶的出納員 --- Splay


傳送門

題目簡述

維護一個數列,同時約定一個下界,當一個元素低於該下界時,將其刪除。統計最終刪去的數的個數
有以下操作:
1. 增加一個元素(若該元素低於下界,則無視該操作
2. 將每一個元素加上一個數
3. 將每一個元素減去一個數
4. 查詢第k大的數

分析

  直接建樹感覺是不可能的(整體操作絕對會Tle),因此,考慮從相對關系上對原數列進行處理。
  既然是以下界(k)來判斷,那么對於整體的加減操作,則可以轉化為對k的減加操作。
  對於刪除節點,只需要在減工資后,將小於k的元素全部刪除即可

代碼

#include <cstdio>
#include <cstdlib>

#define IL inline

using namespace std;

IL int read()
{
int k = 1, sum = 0;
char c = getchar();
for(; '0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; '0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return sum * k;
}

int tot;

struct node
{
node *father;
node *son[2];
int size;
int val;
int cnt;

IL node(int v = 0, node *f = 0)
{
father = f;
son[0] = son[1] = 0;
size = 1;
val = v;
cnt = 0;
}
};
node *root;

IL int size(node *p)
{
return p ? p->size : 0;
}

IL bool son(node *f, node *p)
{
return f ? (f->son[1] == p) : -1;
}

IL void connect(node *f, node *p, bool k)
{
if(!f) root = p; else f->son[k] = p;
if(p) p->father = f;
}

IL void updata(node *p)
{
p->size = size(p->son[0]) + size(p->son[1]) + p->cnt;
}

IL void rotate(node *p)
{
node *f = p->father, *g = f->father;
bool x = son(f, p), y = !x;

connect(f, p->son[y], x);
connect(g, p, son(g, f));
connect(p, f, y);

updata(f);
}

IL void splay(node *p, node *q)
{
for(node *f, *g; p->father != q;)
{
f = p->father;
g = f->father;

if(g == q) rotate(p); else
{
if(son(g, f) ^ son(f, p))
rotate(p), rotate(p);
else
rotate(f), rotate(p);
}
}
updata(p);
}

IL void insert(int val)
{
if(!root) root = new node(val, 0);

for(node *p = root; p; p = p->son[val > p->val])
{
if(p->val == val)
{
++(p->cnt);
splay(p, 0);
return ;
}else
if(!p->son[val > p->val])
p->son[val > p->val] = new node(val, p);
}
}

inline node *find_nxt(int val)
{
node *x = 0;
for(node *p = root; p; p = p->son[val > p->val])
if(p->val >= val)
x = p;
return x;
}

IL void earse_2(int val)
{
node *p = find_nxt(val);
if(!p)
{
tot += size(root);
root = 0;
}else
{
splay(p, 0);
tot += size(p->son[0]);
p->son[0] = 0;
updata(p);
}
}

IL int rankx(int t)
{
for(node *p = root; p;)
{
if(t <= size(p->son[0])) p = p->son[0]; else
if(t - size(p->son[0]) <= p->cnt)
{
splay(p, 0);
return p->val;
}else
{
t -= size(p->son[0]) + p->cnt;
p = p->son[1];
}
}
}

int main()
{
int n = read(), del = read();

char c;
for(int x, sum = 0; n; -- n)
{
scanf(" %c", &c);
x = read();
if(c == 'I')
{
x -= del; // 此處純屬好玩,本可以無視
if(x >= 0) insert(x + sum); // 注意先判斷
}else
if(c == 'A')
{
sum -= x;
}else
if(c == 'S')
{
sum += x;
earse_2(sum);
}else
if(c == 'F')
{
if(size(root) < x) printf("-1\n"); else
printf("%d\n", rankx(size(root) - x + 1) - sum + del);
}
}
printf("%d\n", tot);
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com