洛谷 P2286 [HNOI2004]宠物收养场

题目:宠物收养场

思路:
由于同一时间不可能同时有人和狗,所以只需要建立一棵平衡树,赋予一个属性代表人或狗。
然后对于领养操作,查找前驱后继,取差的绝对值最小,删除即可。

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 80000
#define read(x) scanf("%d",&x)
#define inf (int)1e9
#define md 1000000

struct Node{
	int fa,sz,val;
	int ch[2];
};

int n;
Node a[maxn*10+5];

int rt,cnt,knd;

void push_up(int x) {
	a[x].sz=a[a[x].ch[0]].sz+a[a[x].ch[1]].sz;
}

void rotate(int x) {
	int fa1=a[x].fa,fa2=a[fa1].fa;
	int k=(x==a[fa1].ch[1]);
	a[fa2].ch[fa1==a[fa2].ch[1]]=x,a[x].fa=fa2;
	a[fa1].ch[k]=a[x].ch[k^1],a[a[x].ch[k^1]].fa=fa1;
	a[x].ch[k^1]=fa1,a[fa1].fa=x;
	push_up(fa1),push_up(x);
}

void splay(int x,int k){
	while(a[x].fa!=k) {
		int fa1=a[x].fa,fa2=a[fa1].fa;
		if(k!=fa2) {
			if((a[fa1].ch[0]==x)^(a[fa2].ch[0]==fa1)) rotate(x);
			else rotate(fa1);
		}
		rotate(x);
	}
	if(!k) rt=x;
}

void insert(int x) {
	int u=rt,fu=0;
	while(u) {fu=u,u=a[u].ch[x>a[u].val];}
	u=fu;
	a[++cnt].val=x;
	a[cnt].fa=u;a[cnt].sz++;
	a[u].ch[x>a[u].val]=cnt;
	splay(cnt,0);
}

void find(int x) {
    int u=rt;
    while(a[u].ch[x>a[u].val]&&x!=a[u].val) {
        u=a[u].ch[x>a[u].val];
    }
    splay(u,0);
}

int nxt(int x,int k) {
    find(x);
    int u=rt;
    if((a[u].val<x&&!k)||(a[u].val>x&&k)) return u;
    u=a[u].ch[k];
    while(a[u].ch[k^1]) u=a[u].ch[k^1];
    return u;
}
 
void del(int x) {
    int y=nxt(a[x].val,0),z=nxt(a[x].val,1);find(x);
    splay(y,0),splay(z,y);
	a[z].ch[0]=0;
	a[x].fa=-1;
	cnt--;
}

int main() {
	int ans=0;
	read(n);
	insert(inf);
	insert(-inf);
	for(int i=1;i<=n;i++) {
		
		int x,y;
		read(x),read(y);
		if(cnt==2) insert(y),knd=x;
		else if(knd^x) {
			find(y);
			if(a[rt].val==y) {del(rt);continue;}
			int k1=nxt(y,0),k2=nxt(y,1);
			int s1=a[k1].val,s2=a[k2].val;
			if(abs(y-s1)<=abs(s2-y)) {ans=(ans+abs(y-s1))%md;del(k1);}
			else {ans=(ans+abs(s2-y))%md;del(k2);}
		} else {insert(y);}
	}
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值