Splay求调
查看原帖
Splay求调
903392
T7_Daniel楼主2025/6/21 13:51

样例没过,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);
}
2025/6/21 13:51
加载中...