首页 > 其他分享 > 【NOIP2017 提高组】列队

【NOIP2017 提高组】列队

时间:2022-09-27 16:00:16浏览次数:71  
标签:NOIP2017 idx int 提高 tr son fa 列队 size

[ 【NOIP2017 提高组】列队](https://www.luogu.com.cn/problem/P3960)

将每一行的第1到m-1个和第m列分离出来
分析知这n+1个“区间”要维护弹出第k个和插入最后
使用平衡树,一个区间若没有被算则用[l,r]表示(方伯伯的OJ)

点击查看代码

#include <stdio.h>
#include <string.h>
const int N = 3e5 + 5;
typedef long long LL;
struct Node {
    int son[2], fa;
    LL l, r, size; // l,r 为区间左右端点
} tr[N * 8];
int idx, n, m, q;
void push_up(int u) {
    tr[u].size = tr[tr[u].son[0]].size + tr[tr[u].son[1]].size + (tr[u].r - tr[u].l + 1);
}
void rotate(int x) {
    int y = tr[x].fa, z = tr[y].fa, k = tr[y].son[1] == x;
    tr[tr[z].son[tr[z].son[1] == y] = x].fa = z;
    tr[tr[y].son[k] = tr[x].son[!k]].fa = y;
    tr[tr[x].son[!k] = y].fa = x;
    push_up(y), push_up(x);
}
struct Splay {
    int root;
    void splay(int x, int rt) {
        static int y, z;
        while(tr[x].fa != rt) {
            y = tr[x].fa, z = tr[y].fa;
            if(z != rt) rotate((tr[y].son[1] == x) ^ (tr[z].son[1] == y) ? x : y);
            rotate(x);
        }
        if(!rt) root = x;
    }
    void init(LL l, LL r) {
        root = ++ idx;
        tr[idx].fa = tr[idx].son[0] = tr[idx].son[1] = 0;
        tr[idx].l = l, tr[idx].r = r, tr[idx].size = r - l + 1;
    }
    int build(int fa, int l, int r) {
        if(l > r) return 0;
        int mid = (l + r) >> 1, u = ++ idx;
        tr[u].fa = fa, tr[u].l = tr[u].r = LL(mid) * m;
        tr[u].son[0] = build(u, l, mid - 1);
        tr[u].son[1] = build(u, mid + 1, r);
        push_up(u); return u;
    }
    // 将u的前k个保留,后面的作为返回值的新节点
    int split(int u, int k) {
        int v = ++ idx;
        tr[v].l = tr[u].l + k, tr[v].r = tr[u].r;
        tr[u].r = tr[u].l + k - 1;
        // 将v节点放到u的后继节点的左儿子并旋转到根
        if(tr[u].son[1]) {
            int t = tr[u].son[1];
            while(tr[t].son[0]) t = tr[t].son[0];
            tr[tr[t].son[0] = v].fa = t;
        } else tr[tr[u].son[1] = v].fa = u;
        splay(v, 0);
        return v;
    }
    LL popkth(int k) {
        int u = root, lssz;
        while(u) {
            lssz = tr[tr[u].son[0]].size;
            if(lssz >= k) u = tr[u].son[0];
            else if(lssz + (tr[u].r - tr[u].l + 1) >= k) {
                k -= lssz;
                if(k < tr[u].r - tr[u].l + 1) split(u, k);
                if(k > 1) u = split(u, k - 1);
                break;
            } else k -= lssz + (tr[u].r - tr[u].l + 1), u = tr[u].son[1];
        }
        // 现在u为这个单独的节点,将其删除
        splay(u, 0);
        tr[tr[u].son[0]].fa = tr[tr[u].son[1]].fa = 0;
        if(tr[u].son[0]) {
            int t = tr[u].son[0];
            while(tr[t].son[1]) t = tr[t].son[1];
            splay(t, 0);
            tr[tr[t].son[1] = tr[u].son[1]].fa = t;
            push_up(t);
        } else root = tr[u].son[1];
        return tr[u].l;
    }
    void push(LL val) {
        int u = root, fu = 0;
        while(u) fu = u, u = tr[u].son[1];
        u = ++ idx, tr[u].l = tr[u].r = val, tr[u].fa = fu, tr[u].size = 1;
        if(fu) tr[fu].son[1] = u;
        splay(u, 0);
    }
} tree[N];
int main() {
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; i ++) tree[i].init(m * LL(i - 1) + 1, m * LL(i) - 1);
    tree[0].root = tree[0].build(0, 1, n);
    LL tmp; // 答案
    for(int i = 1, x, y; i <= q; i ++) {
        scanf("%d%d", &x, &y);
        tree[x].push(tree[0].popkth(x));
        printf("%lld\n", tmp = tree[x].popkth(y));
        tree[0].push(tmp);
    }
    return 0;
}

</details>

标签:NOIP2017,idx,int,提高,tr,son,fa,列队,size
From: https://www.cnblogs.com/azzc/p/16734865.html

相关文章

  • 【NOIP2017 提高组]】宝藏
    【NOIP2017提高组】宝藏f[S][i]表示集合S的点构成的生成树,树高为i({i}为0)的最小花费转移:枚举S的子集S'为高度为i-1的树(S'可扩展出S):f[S][i]<-f[S'][i]+cost预处......
  • [luogu p8251] [NOI Online 2022 提高组] 丹钓战
    [P8251NOIOnline2022提高组]丹钓战-洛谷|计算机科学教育新生态(luogu.com.cn)容易发现对于一次查询\([L,R]\),\(L\)一定是第一个入栈的,也是成功的,答案至少为......
  • luogu P1052 [NOIP2005 提高组] 过河
    [NOIP2005提高组]过河题目描述在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳......
  • 如何提高英语听力
    嗨,我是Kasia。欢迎来到OxfordOnlineEnglish。在本节课里,您会学到您要怎样提高您英语听力。您会看到任何人都能用来提高他们英语听力技能的简单、有效的技巧。我们......
  • 应用Lombok 插件--提高使用 POJO 类的效率
    不评价使用Lombok的好坏什么是Lombok?lombok⼀个优秀的Java代码库,简化了Java的编码,为Java代码的精简提供了⼀种⽅式可以自动生成JavaBean的getter,setter,equal......
  • [NOIP2002 提高组] 字串变换
    [NOIP2002提高组]字串变换题目背景本题疑似错题,不保证存在靠谱的多项式复杂度的做法。测试数据非常的水,各种做法都可以通过,不代表算法正确。因此本题题目和数据仅供参......
  • 【办公自动化】正则表达式的入门及提高学习网站
    这个网站有入门101课程,带中文的。强烈推荐!https://regexlearn.com/zh-cn/learn/regex101记录一下学习心得:1、abcd*和abcd+......
  • P2822 [NOIP2016 提高组] 组合数问题
    P2822[NOIP2016提高组]组合数问题题解作者岛田小雅这是一道复杂度非常容易爆炸的问题。我看到这题的第一眼,第一反应是直接按照公式暴力跑。我们看一眼数据范围。如......
  • [NOIP2001 提高组] 统计单词个数
    [NOIP2001提高组]统计单词个数题目描述给出一个长度不超过\(200\)的由小写英文字母组成的字母串(该字串以每行\(20\)个字母的方式输入,且保证每行一定为\(20\)个)。......
  • 洛谷 P1025 [NOIP2001 提高组] 数的划分 (dfs)
    https://www.luogu.com.cn/problem/P1025给定一个n和k,把n拆分成k个数字的和,数字可以相同,但是种类不能相同。求能凑出的数量。输入73输出4明明是一道很简单的dfs,......