luoguP3690 列队

Posted ljc00118

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP3690 列队相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problemnew/show/P3960

作为一个初二蒟蒻要考提高组,先做一下17年的题目

我们发现进行一次操作相当于

  • 把第 x 行的第 y 个弹出记为 a,其余向左移 = splay 中弹出第 y 个
  • 把第 m 列的第 x 个弹出记为 b,其余向上移 = splay 中弹出第 x 个
  • 把 b 插到第 x 行末尾 = splay 在队尾插入 b
  • 把 a 插到第 m 列末尾 = splay 在队尾插入 a

然后对于没有用到的节点先合并着,要用就拆开

#include <bits/stdc++.h>
#define int long long
using namespace std;

typedef unsigned long long ull;
typedef long long ll;

template <typename _T>
inline void read(_T &f) {
    f = 0; _T fu = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();}
    while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();}
    f *= fu;
}

const int N = 300000 + 10;

struct Node {
    int l, r, size, id;
    Node *ch[2];
    Node (int a, int b, int c, int d, Node *e, Node *f) {
        l = a, r = b, size = c, id = d;
        ch[0] = e, ch[1] = f;
    }
}*root[N], *null;

int w[N];
int n, m, q;

void update(Node *u) {
    u -> size = u -> ch[0] -> size + u -> ch[1] -> size + u -> r - u -> l + 1;
}

void rotate(Node *&u, int d) {
    Node *tmp = u -> ch[d];
    u -> ch[d] = tmp -> ch[d ^ 1];
    tmp -> ch[d ^ 1] = u;
    update(u); update(tmp);
    u = tmp;
}

void splay(Node *&u, int k) {
    int ltree = u -> ch[0] -> size;
    if(ltree < k && (ltree + (u -> r - u -> l + 1) >= k)) return;
    int d = k > ltree;
    int k2 = d ? k - ltree - (u -> r - u -> l + 1) : k;
    int ltree2 = u -> ch[d] -> ch[0] -> size;
    if(ltree2 >= k2 || (ltree2 + u -> ch[d] -> r - u -> ch[d] -> l + 1) < k2) {
        int d2 = k2 > ltree2;
        splay(u -> ch[d] -> ch[d2], d2 ? k2 - ltree2 - (u -> ch[d] -> r - u -> ch[d] -> l + 1) : k2);
        if(d == d2) rotate(u, d2);
        else rotate(u -> ch[d], d2);
    }
    rotate(u, d);
}

Node *build(int l, int r) {
    if(l > r) return null;
    if(l == r) return new Node(w[l], w[l], 1, w[l], null, null);
    int mid = (l + r) >> 1;
    return new Node(w[mid], w[mid], r - l + 1, w[mid], build(l, mid - 1), build(mid + 1, r));
}

void merge(Node *&a, Node *&b) {
    if(a == null) a = b, b = null;
    if(b == null) return;
    splay(a, a -> size);
    a -> ch[1] = b;
    update(a);
}

int split(Node *&u, int k) {
    splay(u, k);
    int ltree = u -> ch[0] -> size;
    int K = k - ltree, l = u -> l, r = u -> r;
    if(K != 1) {
        Node *tmp = new Node(l, l + K - 2, K - 1, l, u -> ch[0], null);
        u -> ch[0] = tmp; u -> l = l + K - 1; update(u -> ch[0]);
    }
    if(K != r - l + 1) {
        Node *tmp = new Node(l + K, r, r - l - K + 1, l + K, null, u -> ch[1]);
        u -> ch[1] = tmp; u -> r = l + K - 1; update(u -> ch[1]);
    }
    Node *t2 = u -> ch[1]; u -> ch[1] = null; u -> id = u -> l;
    int ans = u -> id; u = u -> ch[0]; merge(u, t2); return ans;
}

void ins(Node *&u, int x) {
    if(u == null) u = new Node(x, x, 1, x, null, null);
    else {
        splay(u, u -> size);
        u -> ch[1] = new Node(x, x, 1, x, null, null);
        update(u);
    }
}

signed main() {
    null = new Node(0, -1, 0, 0, 0, 0);
    read(n); read(m); read(q);
    for(int i = 1; i <= n; i++) {
        root[i] = new Node(1 + (i - 1) * m, m - 1 + (i - 1) * m, m - 1, 1 + (i - 1) * m, null, null);
    }
    for(int i = 1; i <= n; i++) w[i] = i * m;
    root[0] = build(1, n);
    for(int i = 1; i <= q; i++) {
        int a, b;
        read(a); read(b);
        if(b == m) {
            int ans = split(root[0], a);
            printf("%lld
", ans);
            ins(root[0], ans);
            continue;
        }
        int ans = split(root[a], b);
        printf("%lld
", ans);
        int tmp = split(root[0], a);
        ins(root[a], tmp);
        ins(root[0], ans);
    }
    return 0;
}

以上是关于luoguP3690 列队的主要内容,如果未能解决你的问题,请参考以下文章

LuoguP3690 模板Link Cut Tree (LCT)

LuoguP3690 模板Link Cut Tree (动态树) LCT模板

luoguP3690 模板Link Cut Tree (动态树)[LCT]

[luoguP3960] 列队(动态开点线段树)

[LuoguP2161[ [SHOI2009]会场预约 (splay)

P3690 模板Link Cut Tree (动态树)