网址:https://www.luogu.org/problem/P2286
题意:
宠物店会来宠物和客人,且保证同一时刻在宠物店的只有宠物或者客人,如果来的是客人且其目标值为$b$,则其会选择最接近$b$的宠物值$a$,如果有两个满足要求的,会选小的。如果来的是宠物,其值为$a$,就会选择目标值最靠近的客户,如果有多种可能,选小的。求这些客人领养到的宠物的值的和对$1000000$的模。
题解:
因为题目保证了同一时刻在宠物店的只有宠物或者客人,所以我们可以维护一个$cnt$表示当前$splay$的状态,$cnt$初始值为$0$,来的是宠物就$++cnt$,客人就$--cnt$,根据正负就可以判断是客人树还是宠物树。如果是宠物树,当下一个是宠物时则直接插入$splay$,如果是客人则取走宠物(即累加宠物值和删除宠物)。客人树时同理。不在$splay$中的值查找前驱和后继时,有两种方法,一个是插入,寻找前驱后继再删除,一个是直接查找。本题使用第一种,但是第二种更优。
AC代码:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1.2e5 + 5; #define ll long long struct Splay { int rt, sz; int fa[MAXN], son[MAXN][2], size[MAXN], num[MAXN]; ll val[MAXN]; //private int getson(int x) { return son[fa[x]][1] == x; } void up(int x) { if (x) { size[x] = num[x]; if (son[x][0]) size[x] += size[son[x][0]]; if (son[x][1]) size[x] += size[son[x][1]]; } } void con(int x, int y, int z)//x成为y的z儿子 { if (x) fa[x] = y; if (y) son[y][z] = x; } void rotate(int x) { int fx = fa[x], ffx = fa[fx]; int ffs = getson(fx), fs = getson(x); con(son[x][fs ^ 1], fx, fs); con(fx, x, fs ^ 1); con(x, ffx, ffs); up(fx), up(x); } void splay(int x, int end) { end = fa[end]; int f; while (fa[x] != end) { f = fa[x]; if (fa[f] != end) rotate(getson(x) == getson(f) ? f : x); rotate(x); } if (!end) rt = x; } int newnode(ll x, int f) { int nrt = ++sz; val[nrt] = x; fa[nrt] = f; son[f][x > val[f]] = nrt; size[nrt] = num[nrt] = 1; son[nrt][0] = son[nrt][1] = 0; return nrt; } int pre() { if (num[rt] > 1) return rt; int now = son[rt][0]; while (son[now][1]) now = son[now][1]; splay(now, rt); return now; } int nxt() { if (num[rt] > 1) return rt; int now = son[rt][1]; while (son[now][0]) now = son[now][0]; splay(now, rt); return now; } //public void clear(int x) { fa[x] = son[x][0] = son[x][1] = size[x] = num[x] = val[x] = 0; } void insert(ll x) { if (!rt) { rt = newnode(x, 0); return; } int now = rt, f = 0; while (1) { if (x == val[now]) { ++num[now]; up(now), up(f); splay(now, rt); return; } f = now; now = son[now][x > val[now]]; if (!now) { int tmp = newnode(x, f); up(f); splay(tmp, rt); return; } } } int queryrnk(ll x) { int ans = 0, now = rt; while (1) { if (x < val[now]) { now = son[now][0]; continue; } ans += size[son[now][0]]; if (x == val[now]) { splay(now, rt); return ans + 1; } ans += num[now]; now = son[now][1]; } } void del(ll x) { queryrnk(x); if (num[rt] > 1) { --num[rt], up(rt); return; } else if (!son[rt][0] && !son[rt][1]) { clear(rt), rt = 0; return; } else if (!son[rt][0]) { int tmp = rt; rt = son[rt][1], fa[rt] = 0; clear(tmp); return; } else if (!son[rt][1]) { int tmp = rt; rt = son[rt][0], fa[rt] = 0; clear(tmp); return; } else { int tmp = rt, l = pre(); splay(l, rt); con(son[tmp][1], rt, 1); clear(tmp); up(rt); return; } } ll queryfront(ll x) { insert(x); ll tmp = val[pre()]; del(x); return tmp; } ll queryback(ll x) { insert(x); ll tmp = val[nxt()]; del(x); return tmp; } }; Splay sp; int mod = 1000000; int main() { //freopen("D:\in.txt", "r", stdin); //freopen("D:\out.txt", "w", stdout); int n; scanf("%d", &n); int c, val; sp.insert(1ll << 50); sp.insert((1ll << 50) * (-1)); int cnt = 0; ll ans = 0; for (int i = 0; i < n; ++i) { scanf("%d%d", &c, &val); if (cnt == 0) sp.insert(val); else if (cnt > 0) { if (c == 0) sp.insert(val); else { ll ans1 = sp.queryfront(val), ans2 = sp.queryback(val); if (abs(val - ans1) <= abs(val - ans2)) { sp.del(ans1); ans = (ans + abs(val - ans1)) % mod; } else if (abs(val - ans1) > abs(val - ans2)) { sp.del(ans2); ans = (ans + abs(val - ans2)) % mod; } } } else if (cnt < 0) { if (c == 1) sp.insert(val); else { ll ans1 = sp.queryfront(val), ans2 = sp.queryback(val); if (abs(val - ans1) <= abs(val - ans2)) { sp.del(ans1); ans = (ans + abs(val - ans1)) % mod; } else if (abs(val - ans1) > abs(val - ans2)) { sp.del(ans2); ans = (ans + abs(val - ans2)) % mod; } } } cnt += c ? -1 : 1; } printf("%lld ", ans); return 0; }