写的心累。。
将A操作看为降低工资底线,将S操作看为升高工资底线。那么这样就不用标记下传了。
另外一开始要加一个inf节点,不能再加个-inf节点,因为会被删掉...
写删除的时候要小心,根节点的删除和子树删除不一样。
/* Pigonometry */
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005, inf = 0x3f3f3f3f;
int n, lwb, delta, ans;
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
int son[maxn][2], pre[maxn], val[maxn], size[maxn];
int tot1, tot2, sta[maxn], root;
inline void newnode(int &x, int f, int c) {
x = tot2 ? sta[tot2--] : ++tot1;
son[x][0] = son[x][1] = 0;
pre[x] = f;
val[x] = c;
size[x] = 1;
}
inline void pushup(int x) {
size[x] = size[son[x][0]] + size[son[x][1]] + 1;
}
inline void init() {
tot1 = tot2 = root = 0;
son[0][0] = son[0][1] = pre[0] = val[0] = size[0] = 0;
newnode(root, 0, inf);
pushup(root);
}
inline void rotate(int x) {
int y = pre[x], z = pre[y], type = son[y][1] == x;
pre[son[y][type] = son[x][!type]] = y;
pre[x] = z;
if(z) son[z][son[z][1] == y] = x;
pre[son[x][!type] = y] = x;
pushup(y); pushup(x);
}
inline void splay(int x, int goal) {
while(pre[x] != goal) {
int y = pre[x], z = pre[y];
if(z == goal) rotate(x);
else if(son[z][1] == y ^ son[x][1] == x) rotate(x), rotate(x);
else rotate(y), rotate(x);
}
if(goal == 0) root = x;
}
inline int find(int k) {
int x = root;
while(k != size[son[x][0]] + 1)
if(k <= size[son[x][0]]) x = son[x][0];
else k -= size[son[x][0]] + 1, x = son[x][1];
return x;
}
inline int insert(int c) {
int now = root;
for(; son[now][c > val[now]]; now = son[now][c > val[now]]);
newnode(son[now][c > val[now]], now, c);
splay(son[now][c > val[now]], 0);
return root;
}
inline void trash(int x) {
if(!x) return;
trash(son[x][0]); trash(son[x][1]);
son[x][0] = son[x][1] = pre[x] = val[x] = size[x] = 0;
sta[++tot2] = x;
}
inline void del(int c) {
int x = insert(c);
splay(x, 0);
ans += size[son[x][0]];
trash(son[x][0]);
root = son[x][1];
pre[root] = 0;
sta[++tot2] = x;
pushup(root);
}
inline int findwage(int k) {
k = size[root] - k;
int x = find(k);
return val[x];
}
int main() {
n = iread(); lwb = iread();
init();
while(n--) {
char ch = getchar(); for(; ch < 'A' || ch > 'Z'; ch = getchar());
int k = iread();
if(ch == 'I') {
if(k >= lwb) insert(k + delta);
}
else if(ch == 'A') delta -= k;
else if(ch == 'S') {
delta += k;
del(lwb + delta);
}
else if(ch == 'F') {
if(k > size[root] - 1) printf("-1\n");
else printf("%d\n", findwage(k) - delta);
}
}
printf("%d\n", ans);
return 0;
}
附暴力和mkdata
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int n, lwb, tot, ans, num[maxn];
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline bool cmp(int a, int b) {
return a > b;
}
int main() {
freopen("cashier.in", "r", stdin); freopen("cashier.ans", "w", stdout);
n = iread(); lwb = iread(); ans = 0;
while(n--) {
char ch = getchar(); for(; ch < 'A' || ch > 'Z'; ch = getchar());
int k = iread();
if(ch == 'I') {
if(k >= lwb) num[++tot] = k;
}
else if(ch == 'A') {
for(int i = 1; i <= tot; i++) num[i] += k;
}
else if(ch == 'S') {
sort(num + 1, num + 1 + tot, cmp);
for(int i = 1; i <= tot; i++) {
num[i] -= k;
if(num[i] < lwb) ans += tot - i + 1, tot = i - 1;
}
}
else if(ch == 'F') {
if(k > tot) printf("-1\n");
else {
sort(num + 1, num + 1 + tot, cmp);
printf("%d\n", num[k]);
}
}
}
printf("%d\n", ans);
return 0;
}
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
const int maxv = 100;
inline int rd(int x) {
return rand() % x + 1;
}
int main() {
srand(time(0));
freopen("cashier.in", "w", stdout);
int n = 30, lwb = rd(maxv);
printf("%d %d\n", n, lwb);
while(n--) {
int opt = rd(4);
if(opt == 1) printf("I %d\n", rd(maxv) - 1);
else if(opt == 2) printf("A %d\n", rd(maxv) - 1);
else if(opt == 3) printf("S %d\n", rd(maxv) - 1);
else if(opt == 4) printf("F %d\n", rd(n + 100));
}
return 0;
}