样例没过,Sub 1过了,Sub 0爆零,马蜂自认为良好,有注释。求救。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int Mod=1e6;
struct node{
int s[2];//左右儿子
int fa;//父亲
int v;//节点权值
int cnt;//权值出现次数
int sz;//子树大小
void init(int vv,int pp){//初始化
fa=pp,v=vv;
cnt=sz=1;
}
}tr[N];
int root;//根节点
int idx;//节点数量,动态开点
inline int read(){
int s=0,f=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*f;
}
inline void write(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void pushup(int p){
tr[p].sz=tr[tr[p].s[0]].sz+tr[tr[p].s[1]].sz+tr[p].cnt;
}
inline void rorate(int x){//旋转
int y=tr[x].fa,z=tr[y].fa;
int k=tr[y].s[1]==x;
tr[z].s[tr[z].s[1]==y]=x,tr[x].fa=z;
tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].fa=y;
tr[x].s[k^1]=y,tr[y].fa=x;
pushup(y),pushup(x);
}
inline void splay(int x,int k){//将x转到k,k=0时代表根节点
while(tr[x].fa!=k){
int y=tr[x].fa,z=tr[y].fa;
if(z!=k)
(tr[y].s[0]==x)^(tr[z].s[0]==y)?rorate(x):rorate(y);
rorate(x);
}
if(k==0) root=x;
}
inline void find(int v){//寻找v
int x=root;
while(tr[x].s[v>tr[x].v] && v!=tr[x].v)
x=tr[x].s[v>tr[x].v];
splay(x,0);
}
inline int get_pre(int v){
//求v的前驱,返回节点编号
//找到对应结点之后,去找最左的最右
find(v);//转移到根节点
int x=root;
if(tr[x].v<v) return x;//不存在v
x=tr[x].s[0];//先走到x的左儿子
while(tr[x].s[1]) x=tr[x].s[1];//最左的最右
splay(x,0);//转到顶上
return x;
}
inline int get_suc(int v){
//求v的后继,返回节点编号
//找到对应结点之后,去找最右的最左
find(v);
int x=root;
if(tr[x].v>v) return x;//不存在v
x=tr[x].s[1];//先走到x的右儿子
while(tr[x].s[0]) x=tr[x].s[0];
splay(x,0);//转到顶上
return x;
}
inline void del(int v){
int pre=get_pre(v);
int suc=get_suc(v);//找前驱 & 后继
splay(pre,0);splay(suc,pre);//前驱转到根节点,后继转到前驱一开始的位置
int de=tr[suc].s[0];
if(tr[de].cnt>1){//还有多个
tr[de].cnt--;//减少一次
splay(de,0);//转到根节点,从而更新受影响的
}else{
tr[suc].s[0]=0;//左儿子清空
splay(suc,0);//更新指数大小
}
}
inline void ins(int v){//插入
int x=root,p=0;
while(x && tr[x].v!=v){
p=x,x=tr[x].s[v>tr[x].v];//找到对应位置
}
if(x) tr[x].cnt++;//存在就增加一个
else{
x=++idx;//动态开点
tr[p].s[v>tr[p].v]=x;//记录p的儿子
tr[x].init(v,p);//初始化当前节点
}
splay(x,0);//转到顶上
}
inline void pre(){//放入王牌守门员,即maxn,minn
ins(2147483647);//maxn
ins(-2147483648);//minn
}
int main(){
int n;cin>>n;
int cnt=0,ans=0;//cnt:树的情况:顾客/宠物,ans:答案
pre();//召唤王牌守门员
while(n--){
int opt=read(),x=read();
if(cnt==0) ins(x);//空树直接放入
else if(cnt>0){//只有宠物
if(opt==0) ins(x);//也是宠物
else{
int x1=get_pre(x-1);//前驱
int x2=get_suc(x+1);//后继
int dis1=abs(x-x1);//前面的差
int dis2=abs(x2-x);//后面的差
if(dis1<=dis2){//左<=右,取左
ans=(ans+dis1)%Mod;
del(x1);
}else{//否则取右
ans=(ans+dis2)%Mod;
del(x2);
}
}
}else{//只有顾客
if(opt==1) ins(x);//也是顾客
else{
int x1=get_pre(x-1);//前驱
int x2=get_suc(x+1);//后继
int dis1=abs(x-x1);//前面的差
int dis2=abs(x2-x);//后面的差
if(dis1<=dis2){//左<=右,取左
ans=(ans+dis1)%Mod;
del(x1);
}else{//否则取右
ans=(ans+dis2)%Mod;
del(x2);
}
}
}
cnt=(cnt+(opt==0?1:-1));//如果是宠物就+1,如果是顾客就-1
}
write(ans);
}