zoukankan      html  css  js  c++  java
  • 【ybt金牌导航4-3-3】【luogu P2286】宠物收养所

    宠物收养所

    题目链接:ybt金牌导航4-3-3 / luogu P2286

    题目大意

    有人和动物,会按一定顺序到来。
    人和动物能匹配,如果一个到了,然后另一种有好几个,就选特点值相差最小的,如果有两个,就选比它小的。
    然后如果另一种没有,就只能等。
    匹配会有花费,就是两个特地值相差的大小。

    然后问你花费和,对 1e6 取模。

    思路

    你想想它每个情况会有两种状态,要么是人在等动物,要么是动物在等人。

    那你可以看到选择匹配可以用平衡树的前驱和后继来搞,然后匹配完就删除。

    那你两种情况看似要两个平衡树,但其实一个够了,因为同一时间内只有一种会存在,而且操作差不多,那我们完全可以只开一个。

    然后我这里用的是 splay。
    我才知道,你一开始要插入两个边界,就是这样前驱后继就可以判断有没有,而且不会影响答案。

    代码

    #include<cstdio>
    #include<iostream>
    #define mo 1000000
    #define ll long long 
    
    using namespace std;
    
    struct Tree {
    	ll l, r, fa, val, size;
    }tree[3000001];
    ll n, X, root, dog, people, Y;
    ll tot, lef_root, rig_root;
    ll ans;
    
    bool son__p(ll now) {//询问它是否是它父亲的左儿子
    	return tree[tree[now].fa].l == now;
    }
    
    void rotate(ll now) {//旋转
    	ll father = tree[now].fa;
    	ll grand = tree[father].fa;
    	ll son = son__p(now) ? tree[now].r : tree[now].l;
    	if (grand) son__p(father) ? tree[grand].l = now : tree[grand].r = now;
    	if (son__p(now)) tree[now].r = father, tree[father].l = son;
    		else tree[now].l = father, tree[father].r = son;
    	tree[now].fa = grand;
    	tree[father].fa = now;
    	if (son) tree[son].fa = father;
    }
    
    void splay(ll x, ll target) {//splay上浮操作
    	while (tree[x].fa != target) {
    		if (tree[tree[x].fa].fa != target) {
    			son__p(x) == son__p(tree[x].fa) ? rotate(tree[x].fa) : rotate(x);
    		}
    		rotate(x);
    	}
    	
    	if (!target) root = x;
    }
    
    ll find(ll x) {//看一个值在树中的位置
    	ll now = root;
    	while (now) {
    		if (x == tree[now].val) break;
    		if (x >= tree[now].val) now = tree[now].r;
    			else now = tree[now].l;
    	}
    	if (now != root) splay(now, 0);
    	return now;
    }
    
    void insert(ll x) {//插入点
    	ll now = root, last = 0;
    	while (now) {
    		last = now;
    		tree[now].size++;
    		if (x < tree[now].val) now = tree[now].l;
    			else now = tree[now].r;
    	}
    	
    	tot++;
    	tree[tot].fa = last;
    	tree[tot].val = x;
    	tree[tot].size = 1;
    	if (x < tree[last].val) tree[last].l = tot;
    		else tree[last].r = tot;
    	
    	splay(tot, 0);
    }
    
    void join(ll small, ll big) {//合并子树
    	tree[small].fa = tree[big].fa = 0;
    	ll new_root = small;
    	while (tree[new_root].r)
    		new_root = tree[new_root].r;
    	splay(new_root, 0);
    	tree[new_root].r = big;
    	tree[big].fa = new_root;
    }
    
    void delete_(ll x) {//删除节点
    	splay(x, 0);
    	if (!tree[x].l && tree[x].r) tree[tree[x].r].fa = 0, root = tree[x].r;
    		else if (tree[x].l && !tree[x].r) tree[tree[x].l].fa = 0, root = tree[x].l;
    			else join(tree[x].l, tree[x].r);
    	
    	tree[x].l = tree[x].r = 0;
    }
    
    ll pre(ll x) {//前驱
    	ll now = find(x);
    	now = tree[now].l;
    	while (tree[now].r) {
    		now = tree[now].r;
    	}
    	return tree[now].val;
    }
    
    ll nxt(ll x) {//后继
    	ll now = find(x);
    	now = tree[now].r;
    	while (tree[now].l) {
    		now = tree[now].l;
    	}
    	return tree[now].val;
    }
    
    int main() {
    	insert(2147483647);//边界数据
    	insert(-2147483647);
    	
    	scanf("%lld", &n);
    	for (ll i = 1; i <= n; i++) {
    		scanf("%lld %lld", &X, &Y);
    		
    		if (X == 0) {
    			if (dog >= people) {//不能匹配
    				insert(Y);
    			}
    			else {//匹配
    				insert(Y);
    				
    				ll bef = pre(Y), aft = nxt(Y);
    				if (bef == -2147483647 || (bef != -1 && aft != -1 && 1ll * aft - 1ll * Y < 1ll * Y - 1ll * bef)) {
    					ans = (ans + 1ll * aft - 1ll * Y) % mo;
    					delete_(find(aft));
    					delete_(find(Y));
    				}
    				else {
    					ans = (ans + 1ll * Y - 1ll * bef) % mo;
    					delete_(find(bef));
    					delete_(find(Y));
    				}
    			}
    			dog++;
    		}
    		else {
    			if (dog <= people) {//不能匹配
    				insert(Y);
    			}
    			else {//匹配
    				insert(Y);
    				
    				ll bef = pre(Y), aft = nxt(Y);
    				if (bef == -2147483647 || (bef != -1 && aft != -1 && 1ll * aft - 1ll * Y < 1ll * Y - 1ll * bef)) {
    					ans = (ans + 1ll * aft - 1ll * Y) % mo;
    					delete_(find(aft));
    					delete_(find(Y));
    				}
    				else {
    					ans = (ans + 1ll * Y - 1ll * bef) % mo;
    					delete_(find(bef));
    					delete_(find(Y));
    				}
    			}
    			people++;
    		}
    	}
    	
    	printf("%lld", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    Round robin
    Linux命令之nslookup
    VLAN
    基础网络概念
    python开发_filecmp
    python开发_stat
    python开发_fileinput
    python开发_os.path
    python开发_bisect
    python开发_copy(浅拷贝|深拷贝)_博主推荐
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_4-3-3.html
Copyright © 2011-2022 走看看