[Luogu] 列队

Posted xayata

tags:

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

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

如果 x = 1,相当于维护一条链,每次取出第 k 个数放在序列末尾
假设有 n + m + q 个位置,每个位置有数为 1 ,没有数为 0,
取出后不前移,那么第 k 个数就是第 k 个 1 的位置
初始时 1 ~ n + m - 1 为 1,其他位置为 0,
用线段树维护区间和即可
类似对于这道题把每行看做一条链,最后一列看做一条链
一次操作可以看成对两条链的操作
套用上面的方法即可
注意要动态开点

#include <bits/stdc++.h>

using namespace std;
const int N = 3e5 + 10;

int n, m, Q, N_;
int size[N * 20], lson[N * 20], rson[N * 20];
int root[N], jdjs;
int ins[N];
int now_root;

#define LL long long

LL val[N * 20];
LL Ans1;

#define gc getchar()

inline int read() {
    int x = 0; char c = gc;
    while(c < 0 || c > 9) c = gc;
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = gc;
    return x;
}

int Calc_size(int l, int r) {
    if(now_root != n + 1) {
        if(r <= m - 1) return r - l + 1;
        else {
            if(l <= m - 1) return (m - 1) - l + 1;
            else return 0;
        }
    } else {
        if(r <= n) return r - l + 1;
        else {
            if(l <= n) return n - l + 1;
            else return 0;
        }
    }
    
}

void Sec_A(int l, int r, int & jd, int x) {
    if(!jd) {
        jd = ++ jdjs;
        size[jd] = Calc_size(l, r);
        if(l == r) {
            if(now_root <= n) val[jd] = (LL) 1ll * (now_root - 1) * m + l;    
            else val[jd] = (LL) 1ll * l * m;
        }
    }
    size[jd] --;
    if(l == r) {Ans1 = val[jd]; return ;}
    int mid = (l + r) >> 1;
    if((!lson[jd] && x <= mid - l + 1) || x <= size[lson[jd]]) Sec_A(l, mid, lson[jd], x);
    else {
        if(!lson[jd]) x -= (mid - l + 1);
        else x -= size[lson[jd]];
        Sec_A(mid + 1, r, rson[jd], x);
    }
}

void Ins(int l, int r, int & jd, int whe, LL Num) {
    if(!jd) {
        jd = ++ jdjs;
        size[jd] = Calc_size(l, r);
        if(l == r) val[jd] = Num;
    }
    size[jd] ++;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(whe <= mid) Ins(l, mid, lson[jd], whe, Num);
    else Ins(mid + 1, r, rson[jd], whe, Num);
}

int main() {
    n = read(), m = read(), Q = read();
    N_ = max(n, m) + Q;
    while(Q --) {
        int x = read(), y = read();
        if(y == m) now_root = n + 1, Sec_A(1, N_, root[now_root],x);
        else now_root = x, Sec_A(1, N_, root[now_root], y);
        cout << Ans1 << endl;
        now_root = n + 1; Ins(1, N_, root[n + 1], n + (++ ins[n + 1]), Ans1);
        if(y != m) {
            now_root = n + 1; Sec_A(1, N_, root[now_root], x);
            now_root = x; Ins(1, N_, root[x], m - 1 + (++ ins[x]), Ans1);
        }
    }
    return 0;
}

 

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

luogu 3960 列队

Luogu P3960 列队(动态开点线段树)

luogu3960 列队

Luogu T103180 しろは的军训列队 前缀和

luoguP3690 列队

学术篇NOIP2017 d2t3 列队phalanx splay做法