网址: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;
}