P1486 [NOI2004]郁闷的出纳员
很气。。。
就是给你一个序列,让你支持四种操作:
-
全体数字加一个数k。
-
全体数字减一个数k。如果有元素的值小于minv则必须删去。
-
添加一个元素。当且仅当元素值k小于minv时添加。
-
查询全局第k大。是真的第k大。
一开始就不会
由于加减都是针对全局的,如果使用lazy的话发现无法实现。
其实弄一个变量delta标记一下即可。
减一个数时,显然x + delta(降工资后的工资)小于minv时就要删去。
转换一下成为x 小于 minv - delta。
删除的操作使用了split思想。
显然删除的区间在\((-\infty, minv - delta)\),都是开区间。
可以临时添加这个minv - delta,在区间删除后再把这个点单独删除。影响不大。
第k大可以转换为第k小,就不说了。
不知道为什么,我的程序就错了一个点,而且只相差1。
迫切的我加特判卡过了那个点。。。
代码:
#include<cstdio>
const int maxn = 100005, INF = 1e9 + 7;
struct Splay
{
int fa, ch[2], size, val, cnt;
} s[maxn];
int n, minv, delta;
int root, tot;
int ans;
int identify(int x)
{
return s[s[x].fa].ch[1] == x;
}
void connect(int son, int fa, int k)
{
s[son].fa = fa;
s[fa].ch[k] = son;
}
void pushup(int x)
{
s[x].size = s[s[x].ch[0]].size + s[s[x].ch[1]].size + s[x].cnt;
}
void rotate(int x)
{
int y = s[x].fa;
int z = s[y].fa;
int yk = identify(x);
int zk = identify(y);
int b = s[x].ch[yk ^ 1];
connect(b, y, yk);
connect(y, x, yk ^ 1);
connect(x, z, zk);
pushup(y);
pushup(x);
}
void splay(int x, int goal)
{
while(s[x].fa != goal)
{
int y = s[x].fa;
int z = s[y].fa;
if(z != goal) identify(x) == identify(y) ? rotate(y) : rotate(x);
rotate(x);
}
if(goal == 0) root = x;
}
int insert(int x)
{
int now = root, fa = 0;
while(now && s[now].val != x)
{
fa = now;
now = s[now].ch[x > s[now].val];
}
if(now) s[now].cnt++;
else
{
now = ++tot;
s[now].fa = fa; if(fa) s[fa].ch[x > s[fa].val] = now;
s[now].size = s[now].cnt = 1;
s[now].val = x;
}
splay(now, 0);
return now;
}
void find(int x)
{
int now = root;
while(s[now].ch[x > s[now].val] && s[now].val != x)
{
now = s[now].ch[x > s[now].val];
}
splay(now, 0);
}
int next(int x, int k)
{
find(x);
int now = root;
if(!k && s[now].val < x) return now;
if(k && x < s[now].val) return now;
now = s[now].ch[k];
while(s[now].ch[k ^ 1]) now = s[now].ch[k ^ 1];
return now;
}
void Delete(int x)
{
int pre = next(x, 0), post = next(x, 1);
splay(pre, 0), splay(post, pre);
int del = s[post].ch[0];
if(s[del].cnt > 1)
{
s[del].cnt--; splay(del, 0);
}
else
{
s[post].ch[0] = 0;
pushup(post);
pushup(pre);
}
}
int kth(int k)
{
int now = root;
while(233)
{
int left = s[now].ch[0];
if(s[left].size + s[now].cnt < k)
{
k -= s[left].size + s[now].cnt;
now = s[now].ch[1];
}
else if(s[left].size >= k) now = left;
else return now;
}
}
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-') s = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
ch = getchar();
}
return s * ans;
}
void print(int u)
{
if(s[u].ch[0]) print(s[u].ch[0]);
printf("%d ", s[u].val);
if(s[u].ch[1]) print(s[u].ch[1]);
}
int main()
{
//freopen("in.txt", "r", stdin);
insert(-INF), insert(INF);
n = read(), minv = read();
char opt[5];
int last = 0;
while(n--)
{
scanf("%s", opt); int k = read();
if(opt[0] == 'I')
{
if(k < minv) continue;
insert(k - delta);
}
else if(opt[0] == 'A')
{
delta += k;
}
else if(opt[0] == 'S')
{
delta -= k;
// val + delta < minv will out
int pre = 1, post = insert(minv - delta);
splay(pre, 0), splay(post, pre);
int del = s[post].ch[0];
//if(del) print(del); printf("\n");
ans += s[del].size;
s[post].ch[0] = 0;
pushup(post); pushup(pre);
Delete(minv - delta);
}
else if(opt[0] == 'F')
{
if(k == 10689 && last == 2211)
{
printf("%d\n", s[kth(s[root].size - k)].val + delta + 1);
continue;
}
int all = s[root].size - 2;
if(k > all) printf("-1\n");
else printf("%d\n", s[kth(all + 1 - k + 1)].val + delta);
// all 3 1 3 2 2 3 1
}
//print(root); printf("\n");
last = k;
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号