• 【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;
    }
    
  • 相关阅读:
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 获取指定进程的输入命令行
    dotnet 获取指定进程的输入命令行
    PHP sqrt() 函数
    PHP sinh() 函数
    PHP sin() 函数
    PHP round() 函数
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_4-3-3.html
Copyright © 2020-2023  润新知