zoukankan      html  css  js  c++  java
  • NOIP 2017 列队 (Splay)

    题目

    题目描述

    Sylvia 是一个热爱学习的女孩子。

    前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。

    Sylvia 所在的方阵中有n*m名学生,方阵的行数为n,列数为m

    为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从1n*m编上了号码(参见后面的样例)。即:初始时,第i行第j列 的学生的编号是(i - 1) * m + j

    然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了q件这样的离队事件。每一次离队事件可以用数对(x, y) (1<=x<=n, 1<=y<=m)描述,表示第x行第y列的学生离队。

    在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达这样的两条指令:

    向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条指令之后,空位在第x行第m列。

    向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条指令之后,空位在第n行第m列。

    教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后,下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第n行 第m列一个空位,这时这个学生会自然地填补到这个位置。

    因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学的编号是多少。

    注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后方阵中同学的编号可能是乱序的。

    输入输出格式

    输入格式:

    输入共q+1行。

    1行包含3个用空格分隔的正整数n,m,q,表示方阵大小是nm列,一共发生了`q次事件。

    接下来q行按照事件发生顺序描述了q件事件。每一行是两个整数x,y,用一个空格分隔,表示这个离队事件中离队的学生当时排在第x行第y列。

    输出格式:

    按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学生的编号。

    输入输出样例

    输入样例:
    2 2 3 
    1 1 
    2 2 
    1 2
    
    输出样例:
    1
    1
    4
    

    题解

    这道题我用splay做

    观察到每次操作的时候,队列的变化是先向左,然后最后一列向上

    我们考虑,每一行用一颗splay来维护,而最后一列单独用一棵splay来维护

    每次操作就可以暴力模拟了

    但是这样很可能会MLE

    解决方案:

    观察到最初每一行编号是连续的,那么splay中每一个结点作为一个区间,

    需要单独用一个结点的时候就将区间分割

    代码 Code

    #include<cstdio>
    using namespace std;
    long long f(-1);
    inline char GetCharacter() {
    	static char buf[2000000], *p1 = buf, *p2 = buf;
    	return (p1 == p2) &&
    	       (p2 = (p1 = buf) + fread(buf, 1, 2000000, stdin), p1 == p2) ? 
    	       EOF : *p1++;
    }
    #define IS_DIGIT(c) (c >= '0' && c <= '9')
    inline void Read(long long &x) {
    	f = 1, x = 0;
    	static char c = GetCharacter();
    	while (!IS_DIGIT(c)) {
    		if (c == '-') f = -1;
    		c = GetCharacter();
    	}
    	while (IS_DIGIT(c)) x = x * 10 + c - '0', c = GetCharacter();
    	x *= f;
    }
    #undef IS_DIGIT
    struct node {
        long long l, r, size;
        node *left, *right, *father;
        node(const long long &le, const long long &ri) {
            l = le, r = ri, size = r - l + 1;
            left = right = father = NULL;
        }
    };
    class splay_tree {
        public:
            node *root;
        private:
            inline void update(register node *x) {
                if (x) x->size = (x->left ? x->left->size : 0) + 
                                 (x->right ? x->right->size : 0) + 
                                 x->r - x->l + 1ll;
            }
            inline void left_rotate(register node *x) {
                register node *y = x->father;
                y->right = x->left;
                if (x->left) x->left->father = y;
                x->father = y->father;
                if (y->father) {
                    if (y == y->father->left) y->father->left = x;
                    else y->father->right = x;
                }
                x->left = y;
                y->father = x;
                update(y), update(x);
            }
            inline void right_rotate(register node *x) {
                register node *y = x->father;
                y->left = x->right;
                if (x->right) x->right->father = y;
                x->father = y->father;
                if (y->father) {
                    if (y == y->father->right) y->father->right = x;
                    else y->father->left = x;
                }
                x->right = y;
                y->father = x;
                update(y), update(x);
            }
            inline void splay(register node *x, const node *target=NULL) {
                register node *y;
                while (x->father != target) {
                    y = x->father;
                    if (x == y->left) {
                        if (y->father != target && y == y->father->left) 
                          right_rotate(y);
                        right_rotate(x);
                    } else {
                        if (y->father != target && y == y->father->right) 
                          left_rotate(y);
                        left_rotate(x);
                    }
                }
                if (!target) root = x;
            }
            inline node *split(register node *x,const long long &rnk) {
                if (1ll < rnk && x->r - x->l + 1ll > rnk) {
                    register node *y = new node(x->l + rnk - 1ll, 
                                                x->l + rnk - 1ll), 
                                  *z = new node(x->l + rnk, x->r);
                    x->r = x->l + rnk - 2ll, x->size = x->r - x->l + 1ll;
                    z->right = x->right;
                    if (x->right) x->right->father = z;
                    x->right = NULL;
                    y->father = x->father;
                    if (x->father) {
                        if (x == x->father->right) x->father->right = y;
                        else x->father->left = y;
                    } else root = y;
                    y->left = x, y->right = z;
                    x->father = z->father = y;
                    update(x), update(z), update(y);
                    return y;
                } else if (x->l == x->r) {
                    return x;
                } else if (rnk == 1ll) {
                    register node *y = new node(x->l, x->l);
                    ++x->l, --x->size;
                    y->father = x->father;
                    if (x->father) {
                        if (x == x->father->left) x->father->left = y;
                        else x->father->right = y;
                    } else root = y;
                    y->left = x->left;
                    if (x->left) x->left->father = y;
                    x->left = NULL;
                    x->father = y, y->right = x;
                    update(x), update(y);
                    return y;
                } else {
                    register node *y = new node(x->r, x->r);
                    --x->r, --x->size;
                    y->father = x->father;
                    if (x->father) {
                        if (x == x->father->right) x->father->right = y;
                        else x->father->left = y;
                    } else root = y;
                    y->right = x->right;
                    if (x->right) x->right->father = y;
                    x->right = NULL;
                    x->father = y, y->left = x;
                    update(x), update(y);
                    return y;
                }
            }
            inline node *erase(register node *x) {
                splay(x);
                if (!x->left && !x->right) {
                    root = NULL;
                    return x;
                } else if (!x->right) {
                    root = x->left;
                    root->father = NULL;
                    x->left = NULL;
                    x->size = x->r - x->l + 1;
                    return x;
                } else if (!x->left) {
                    root = x->right;
                    root->father = NULL;
                    x->right = NULL;
                    x->size = x->r - x->l + 1;
                    return x;
                } else {
                    register node *y = x->right;
                    while (y->left) y = y->left;
                    splay(y, x);
                    y->left = x->left;
                    x->left->father = y;
                    root = y, y->father = x->left = x->right = NULL;
                    update(root);
                    x->size = x->r - x->l + 1;
                    return x;
                }
            }
        public:
            splay_tree() {
                root = NULL;
            }
            inline void push_back(const long long &l, const long long &r) {
                register node *x = root;
                if (!x) {
                    root = new node(l,r);
                } else {
                    while (x->right) x = x->right;
                    splay(x);
                    x->right = new node(l, r);
                    x->right->father = x;
                    update(x);
                }
            }
            inline void push_back(register node *x) {
                register node *y = root, *z = NULL;
                while (y) {
                    z = y;
                    y = y->right;
                }
                if (z) {
                    splay(z);
                    z->right = x, x->father = z;
                    update(z);
                } else {
                    root = x;
                }
            }
            inline node *pop(long long rnk) {
                register node *x = root;
                while (1) {
                    if (x->left) {
                        if (x->left->size >= rnk) x = x->left;
                        else {
                            rnk -= x->left->size;
                            if (x->r - x->l + 1 >= rnk) break;
                            else rnk -= x->r - x->l + 1, x = x->right;
                        }
                    } else {
                        if (x->r - x->l + 1 >= rnk) break;
                        else rnk -= x->r - x->l + 1, x = x->right;
                    }
                }
                return erase(split(x, rnk));
            }
    };
    long long n, m, q, t1, t2;
    splay_tree S[300010];
    int main(int argc, char **argv) {
        Read(n), Read(m), Read(q);
        for (register int i(1); i <= n; ++i) 
          S[i].push_back(1ll + (i - 1ll) * m, i * m - 1);
        for (register int i(1); i <= n; ++i) S[0].push_back(i * m, i * m);
        while (q--) {
            Read(t1), Read(t2);
            if (t2 == m) {
                register node *x = S[0].pop(t1);
                printf("%lld
    ", x->l);
                S[0].push_back(x);
            } else {
                register node *x = S[t1].pop(t2);
                printf("%lld
    ", x->l);
                S[t1].push_back(S[0].pop(t1)), S[0].push_back(x);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    手写web框架之加载配置项目
    JAVA中注解的实现原理
    使用Mock 测试 controller层
    如何写resultful接口
    RSA加密、解密、签名、验签的原理及方法
    AES256位加密
    聊聊分布式事务,再说说解决方案
    分布式锁简单入门以及三种实现方式介绍
    redis总结(面试中容易遇到的)
    字符串匹配的KMP算法
  • 原文地址:https://www.cnblogs.com/forth/p/9493288.html
Copyright © 2011-2022 走看看