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;
    }
    
  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_4-3-3.html
Copyright © 2011-2022 走看看