P2286 [HNOI2004]宠物收养场

我是题面

题意简单明了,两种数,如果加入一个数的时候有另一种数还存在,那就取出另一种数中与这个数差值的绝对值最小的将其删除(多个则取较小),并对答案产生它们差值的绝对值的贡献,如果没有另一种数存在,那就先将这个数存下

平衡树裸题,直接两个平衡树维护就ok了,一个也能维护,稍麻烦一点

线段树好像也可做,我没写,应该不难

我写的是Splay,把Splay用结构体封装好,开两个Splay异常好写

下面放代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 80005
#define mo 1000000
using namespace std;

inline ll read(){
	ll a=0;int f=0;char p=gc();
	while(!isdigit(p)){f|=p=='-';p=gc();}
	while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
	return f?-a:a;
}int n;ll ans;

struct ahaha{  //Splay的结构体
	struct ahaha1{
		int sz,cnt,ch[2];ll v;
	}t[maxn];int rt,tot,f[maxn];
	#define lc t[i].ch[0]
	#define rc t[i].ch[1]
	inline int get(int i){return i==t[f[i]].ch[1];}
	inline void update(int i){
		t[i].sz=t[i].cnt+t[lc].sz+t[rc].sz;
	}
	inline void del(int i){
		t[i].v=t[i].sz=t[i].cnt=f[i]=0;
	}
	inline int newnode(ll v){
		int i=++tot;
		t[i].sz=t[i].cnt=1;t[i].v=v;
		return i;
	}
	inline void rotate(int x){
		int y=f[x],z=f[y],k=get(x);
		f[x]=z;f[t[x].ch[k^1]]=y;f[y]=x;
		if(z)t[z].ch[y==t[z].ch[1]]=x;
		t[y].ch[k]=t[x].ch[k^1];t[x].ch[k^1]=y;
		update(y);update(x);
	}
	void Splay(int x){
		for(int y=f[x];f[x];rotate(x),y=f[x]){
			if(f[y])rotate(get(x)==get(y)?y:x);
			rt=x;
		}
	}
	void insert(ll v){
		int i=rt,k;
		if(!rt){rt=newnode(v);return;}
		while(1){
			k=v>t[i].v;
			if(v==t[i].v){
				++t[i].sz;++t[i].cnt;
				Splay(i);return;
			}
			if(!t[i].ch[k]){
				t[i].ch[k]=newnode(v);f[t[i].ch[k]]=i;
				Splay(t[i].ch[k]);return;
			}
			i=t[i].ch[k];
		}
	}
	void find(ll v){
		int i=rt;
		while(1){
			if(v<t[i].v){
				i=lc;
				if(!i)return;
			}
			else{
				if(!rc||v==t[i].v){
					Splay(i);return ;
				}
				i=rc;
			}
		}
	}
	inline void earase(ll v){
		find(v);int old=rt,i=rt;
		if(t[rt].cnt!=1){--t[rt].cnt;return;}
		if(t[rt].sz==1){del(rt);rt=0;return;}
		if(!lc){rt=rc;f[rt]=0;del(old);return;}
		if(!rc){rt=lc;f[rt]=0;del(old);return;}
		i=lc;while(rc)i=rc;Splay(i);
		t[rt].ch[1]=t[old].ch[1];f[t[rt].ch[1]]=rt;
		del(old);update(rt);
	}
	ll pre(ll v){
		int i=rt;ll maxa=-1;
		while(i){
			if(t[i].v==v)return v;
			if(t[i].v<v){
				maxa=max(maxa,t[i].v);
				i=rc;
			}
			else i=lc;
		}
		return maxa;
	}
	ll next(ll v){
		int i=rt;ll mina=2147483649;
		while(i){
			if(t[i].v==v)return v;
			if(t[i].v>v){
				mina=min(mina,t[i].v);
				i=lc;
			}
			else i=rc;
		}
		return mina;
	}
}t1,t2;

inline void solve_1(){
	ll v=read();
	if(!t2.rt)  //如果没有另一种数,先存起来
		t1.insert(v);
	else{
		ll pre=t2.pre(v),next=t2.next(v); //查询前后缀,没有前缀则前缀为-1,没有后缀则后缀为2147483649
		if(pre==-1){
			ans=(ans+next-v)%mo;
			t2.earase(next);return;
		}
		if(next==2147483649){
			ans=(ans+v-pre)%mo;
			t2.earase(pre);return;
		}
		if(v-pre<=next-v){   //按照题意取较小,然后删除就可以了
			ans=(ans+v-pre)%mo;
			t2.earase(pre);return;
		}
		else{
			ans=(ans+next-v)%mo;
			t2.earase(next);return;
		}
	}
}
inline void solve_2(){  //同上
	ll v=read();
	if(!t1.rt)
		t2.insert(v);
	else{
		ll pre=t1.pre(v),next=t1.next(v);
		if(pre==-1){
			ans=(ans+next-v)%mo;
			t1.earase(next);return;
		}
		if(next==2147483649){
			ans=(ans+v-pre)%mo;
			t1.earase(pre);return;
		}
		if(v-pre<=next-v){
			ans=(ans+v-pre)%mo;
			t1.earase(pre);return;
		}
		else{
			ans=(ans+next-v)%mo;
			t1.earase(next);return;
		}
	}
}

int main(){
	n=read();
	while(n--){
		int zz=read();
		switch(zz){
			case 0:solve_1();break;
			case 1:solve_2();break;
		}
	}
	printf("%lld
",ans);
	return 0;
}

不要抄代码哦

原文地址:https://www.cnblogs.com/hanruyun/p/10248973.html