首页 > 其他分享 >[lnsyoj284/luoguP2286/HNOI2004]宠物收养场

[lnsyoj284/luoguP2286/HNOI2004]宠物收养场

时间:2024-06-15 22:10:23浏览次数:26  
标签:lnsyoj284 return int tr LL luoguP2286 else HNOI2004 key

题意

原题链接
每个宠物和领养人有一个对应的特点值\(a\),当领养人过多时,若添加一个特点值为\(a_p\)的宠物,则查询收养店中特点值最接近\(a_p\),为\(a_q\)的领养人(\(<a_p\)的值优先),将答案累加\(|a_q - a_p|\),然后删除该领养人,否则在收养店中添加一个领养人。反之亦然。求最终的答案\(\bmod 1000000\)的结果,保证不存在两个特点值相同的领养人或两个特点值相同的宠物。

sol

归纳题意,我们发现我们需要四个操作:

  1. 插入一个数
  2. 删除一个数
  3. 查询前驱
  4. 查询后继

这四个操作可以直接使用Treap完成,具体请移步[lnsyoj118/luoguP3369]普通平衡树
需要注意的是,本题中的前驱/后继与P3369所述不完全相同,本题中前驱/后继可以与查询数\(x\)相等,因此在查询时需要做一定的修改
具体地,以查询前驱为例,在\(x<u.key\)时,说明前驱不存在于右子树,否则说明前驱可能为该节点或存在于右子树,查询后继同理。
本题保证值不重复,因此不需要使用\(cnt\),同时,本题不需要查询排名,因此不需要使用\(size\)。但是,由于本题需要判断Treap是否为空,因此需要单独开两个变量来记录当前Treap内存储的数据类型及线段树中的节点数量(不包含哨兵节点)

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>

using namespace std;
typedef long long LL;

const int N = 80005, mod = 1000000;
const LL INF = 1e18;

struct node{
    int l, r;
    LL key, val;
}tr[N];

int n;
int root, size, idx;
int state;
LL ans;

int create(LL key){
    tr[ ++ idx].key = key;
    tr[idx].val = rand();
    return idx;
}

void zig(int &u){
    int p = tr[u].l;
    tr[u].l = tr[p].r, tr[p].r = u, u = p;
}

void zag(int &u){
    int p = tr[u].r;
    tr[u].r = tr[p].l, tr[p].l = u, u = p;
}

void build(){
    create(-INF), create(INF);
    tr[1].r = 2;
    root = 1;
}

void insert(int &u, LL key){
    if (!u) u = create(key);
    else {
        if (key < tr[u].key){
            insert(tr[u].l, key);
            if (tr[tr[u].l].val > tr[u].val) zig(u);
        }
        else {
            insert(tr[u].r, key);
            if (tr[tr[u].r].val > tr[u].val) zag(u);
        }
    }
}

void erase(int &u, LL key){
    if (!u) return ;
    else if (key == tr[u].key) {
        if (tr[u].l || tr[u].r){
            if (!tr[u].r || tr[tr[u].l].val > tr[tr[u].r].val){
                zig(u);
                erase(tr[u].r, key);
            }
            else {
                zag(u);
                erase(tr[u].l, key);
            }
        }
        else u = 0;
    }
    else if (key < tr[u].key) erase(tr[u].l, key);
    else erase(tr[u].r, key);
}

LL get_prev(int u, LL key){
    if (!u) return -INF;
    if (key < tr[u].key) return get_prev(tr[u].l, key);
    else return max(tr[u].key, get_prev(tr[u].r, key));
}

LL get_next(int u, LL key){
    if (!u) return INF;
    if (key > tr[u].key) return get_next(tr[u].r, key);
    else return min(tr[u].key, get_next(tr[u].l, key));
}

int main(){
    scanf("%d", &n);
    build();
    while (n -- ){
        int op;
        LL key;
        scanf("%d%lld", &op, &key);
        if (state == -1) {
            state = op;
            insert(root, key);
            size ++ ;
        }
        else if (state == op) insert(root, key), size ++ ;
        else {
            LL pr = get_prev(root, key), ne = get_next(root, key);
            LL res = min(abs(key - pr), abs(key - ne));
            LL del;
            if (res == abs(key - pr)) del = pr;
            else del = ne;
            erase(root, del);
            ans = (ans + res) % mod;
            size -- ;
            if (!size) state = -1;
        }
    }
    printf("%lld\n", ans);

    return 0;
}

蒟蒻犯的若至错误

  • 插入节点时,没有将节点地址赋给新开的节点

标签:lnsyoj284,return,int,tr,LL,luoguP2286,else,HNOI2004,key
From: https://www.cnblogs.com/XiaoJuRuoUP/p/18249829/lnsyoj284_luoguP2286

相关文章

  • P2285 [HNOI2004] 打鼹鼠
    题目:链接:https://www.luogu.com.cn/problem/P2285这题感觉如果想不到递推关系可能会很麻烦,因为我之前想到的关系就是用dp存:包含三个维度:times,x,y,即dp[times][x][y]来存,然后递推。但是如果把dp看作是以p结尾的抓到的耗子数量时就会方便很多同时要注意,每次到一个点的时候先立为1......
  • 洛谷 P2290 [HNOI2004] 树的计数(Prufer序列,Cayley 公式)
    传送门解题思路关于Prufer序列的构造,见OI-wiki这里直接放结论:一个Prufer序列与一个无根树一一对应度数为\(d_i\)的节点在序列中出现了\(d_i-1\)次\(\sum(d_i-1)=n-2\)n个点的完全图的生成树有\(n^{n-2}\)种所以相当于n-2个数(有重复的)进行全排列,答案即为:\[\frac......
  • [刷题笔记] Luogu P2285 [HNOI2004] 打鼹鼠
    ProblemAnalysis我们初始可以任意决定机器人的位置,状态很多,暴力显然会寄掉。不妨先贪心的思考一下。我们肯定希望机器人初始在最先出现鼹鼠的洞,因为出现在没有鼹鼠的洞是无效的。题目保证输入数据是严格按照出现时间递增顺序给出。定义\(f_i\)表示前\(i\)只鼹鼠最多能打到......
  • P2292 [HNOI2004] L 语言
    给出字典(个数为\(n\))和文章(个数为\(m\)),求文章最大匹配前缀。\(n\leq20,m\leq50\),\(|s|\leq20,|t|\leq2\times10^6\)首先想到用AC自动机,在每个字串结尾标记串......
  • [HNOI2004] L 语言 题解(AC 自动机上 dp)
    前言:原版数据超弱,爆搜就能过(即洛谷里面80分的数据),在此不多说,这里讲的是正解。(如果不是正解我还敢写题解吗)唔······话说洛谷里的题解用的都有状压,蒟蒻表示这题不......