zoukankan      html  css  js  c++  java
  • 洛谷 P3960 列队

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

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

    Sylvia 所在的方阵中有(n imes m)名学生,方阵的行数为n,列数为m。

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

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

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

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

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

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

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

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

    考虑用线段树计算每一行第x个人的位置,因为n和m都很大,所以要动态开点,线段树的最长长度就是(max(n,m)+p)

    计算第x人的位置很好算,维护一个区间内有多少个人被删除掉,查询的时候用类似于主席树的方法查询就可以了

    这样删除操作也就说完了

    而添加时我们开n+1个vector,1~n维护前m-1个人,第n+1维护最后一列,这是因为我们每次操作是先左移再上移

    对于一对(x,y),如果(y=m),则只需要上移,所以直接在第n+1个vector里操作然后把这个数丢到vector最后就好了;否则就要先左移,需要查出第x个vector的第y个,删掉后丢到vector最后,然后上移,在第n+1个vector进行类似的操作

    然后算编号也是很好算的,左移操作中如果我们得到的位置(ans <= m-1),那么编号为((x-1)*n+ans),否则为vector中第([x][ans-m])个数;上移操作中如果(ans <= n),那么编号为(ans*m),否则为vector中第([n+1][ans-n-1])个数(vector下标是从0开始的)

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #define LL long long
    const int N = 3e5;
    using namespace std;
    int n,m,q,rt[N + 5],lc[N * 20 + 5],rc[N * 20 + 5],len,node_cnt;
    vector <LL> d[N + 5];
    struct Seg
    {
        int del[N * 20 + 5];
        int query(int k,int l,int r,int x)
        {
            if (l == r)
                return l;
            int mid = l + r >> 1,y = mid - l + 1 - del[lc[k]];
            if (y >= x)
                return query(lc[k],l,mid,x);
            else
                return query(rc[k],mid + 1,r,x - y);
        }
        void change(int &k,int l,int r,int x)
        {
            if (!k)
                k = ++node_cnt;
            if (l == r)
            {
                del[k]++;
                return;
            }
            int mid = l + r >> 1;
            if (x <= mid)
                change(lc[k],l,mid,x);
            else
                change(rc[k],mid + 1,r,x);
            del[k] = del[lc[k]] + del[rc[k]];
        }
        LL ask1(int x,LL y)
        {
            LL ans = query(rt[n + 1],1,len,x);      
            change(rt[n + 1],1,len,ans);
            if (ans <= n)
                ans *= 1ll * m;
            else
                ans = d[n + 1][ans - n - 1];
            d[n + 1].push_back(y ? y : ans);
            return ans;
        }
        LL ask2(int x,int y)
        {
            LL ans = query(rt[x],1,len,y);
            change(rt[x],1,len,ans);
            if (ans <= m - 1)
                ans = 1ll * (x - 1) * m + ans;
            else
                ans = d[x][ans - m];
            d[x].push_back(ask1(x,ans));
            return ans;
        }
    }tree;
    int main()
    {
        scanf("%d%d%d",&n,&m,&q);
        len = max(n,m) + q;
        int x,y;
        for (int i = 1;i <= q;i++)
        {
            scanf("%d%d",&x,&y);
            if (y == m)
                printf("%lld
    ",tree.ask1(x,0));
            else
                printf("%lld
    ",tree.ask2(x,y));
        }
        return 0;
    }
    
  • 相关阅读:
    js dom
    js Number string
    jq ajax数据交互
    js date 和 math
    js中英文网页切换
    日常使用
    php求和
    empty()
    时间戳、日期相互转换
    数组转字符串之间相互转换
  • 原文地址:https://www.cnblogs.com/sdlang/p/13068271.html
Copyright © 2011-2022 走看看