【Luogu P3960】NOIP2017 day2T3 列队

题目链接

题目描述

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

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

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

为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×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 想要计算每一次离队事件中,离队的同学 的编号是多少。

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

题解

如果用Splay暴力的话,这题思维难度就很低了。

容易发现:每次都是指定的学生离开后,与之同行的最后面的一个从最后一列被拿出来到这一行的第m-1个(其他依次前移),然后再把指定学生扔到最后一列的最后一个。
如果我们建 n+1 棵Splay,每一行的前m-1个构成一颗,最后一列是一棵的话,
那么这就涉及到了Splay的删除,插入,查询第k个数的操作。
当然,这样会爆空间。
所以我们要把每一行序号连续的先给他合并起来,由于询问数较小,所以最后空间不会超过 4q 。

P.S. : 如果你码力不行,那么千万别去写一些可有可无的优化。本人就因为想重复利用一下空间就WA了一上午,还是去掉优化才过的……(还要记得开long long..)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch-48);
    return x*t;
}
typedef long long ll;
#define __ NULL
#define ls son[0]
#define rs son[1]
struct node{
    node* son[2];
    node* fa;int size;
    ll l;ll r;
    inline void clear(){ls=rs=fa=__;size=0;l=r=0;}
};
#define get_son(a) (a->fa->rs==a)
#define get_size(a) (a==__? 0:a->size)
const int N=2e6+10;
node pool[N<<2];int cnt;
node* rt[N];
int n,m,q;
ll ans=0;
ll NOW;
inline void update(node* now)
{
    if(now!=__) now->size=now->r-now->l+1+get_size(now->ls)+get_size(now->rs);
    return ;
}
inline void rotate(node* u)
{
    if(u==__||u->fa==__) return ;
    int k=get_son(u);register node* v=u->fa;
    v->son[k]=u->son[k^1];
    if(u->son[k^1]!=__) u->son[k^1]->fa=v;
    if(v->fa!=__) v->fa->son[get_son(v)]=u;
    u->fa=v->fa;v->fa=u;u->son[k^1]=v;
    update(v);
    return ;
}
inline void Splay(node* now,node* goal)
{
    for(;now->fa!=goal;rotate(now))
    {
        if(now->fa->fa==goal) continue;
        if(get_son(now->fa)==get_son(now))rotate(now->fa);
        else rotate(now);
    }
    update(now);
    return ;
}
inline void insert(node* &rt,ll num)
{
    register node* now=rt;register node* fa=__;
    while(now!=__)  {fa=now;now=now->rs;}
    now=&pool[cnt++];
    now->clear();now->fa=fa;now->l=now->r=num;now->size=1;
    if(fa!=__) fa->rs=now;
    Splay(now,__);
    rt=now;
}
inline node* find(node* u,int &k,int num)
{
    while(k)
    {
        register ll sl=get_size(u->ls);
        if(sl>=k)   u=u->ls;
        else if(get_size(u)-get_size(u->rs)>=k) {k-=sl;ans=u->l+k-1;break;}
        else {k-=(get_size(u)-get_size(u->rs));u=u->rs;}
    }
    Splay(u,__);
    rt[num]=u;
    return u;
}
inline node* Pre(node* u){if(u->ls==__) return __;u=u->ls;while(u->rs!=__) u=u->rs;return u;}
inline void Del(node* u,int num)
{
    NOW=u->l;
    register node* v=Pre(u);
    if(v!=__){Splay(v,__);rt[num]=v;}
    if(v==__){
        if(u->rs!=__) rt[num]=u->rs,u->rs->fa=__,u->clear();
        else rt[num]=__;
    }
    else{
        v->rs=u->rs;if(u->rs!=__) u->rs->fa=v;u->clear();update(v);
    }
}
inline node* split(node* u,int k,int num)
{
    if(u->r==u->l) return u;
    register node *a=__,*b=__;
    if(k==1){
        a=&pool[cnt++];a->clear();a->l=a->r=u->l;a->fa=u;a->ls=u->ls;u->l++;
        if(u->ls!=__) u->ls->fa=a;u->ls=a;update(a);update(u);Splay(a,__);rt[num]=a;
        return a;
    }
    if(k==u->r-u->l+1){
        a=&pool[cnt++];a->clear();a->l=a->r=u->r;a->fa=u;a->rs=u->rs;u->r--;
        if(u->rs!=__) u->rs->fa=a;u->rs=a;update(a);update(u);Splay(a,__);rt[num]=a;
        return a;
    }
    a=&pool[cnt++];a->clear();b=&pool[cnt++];b->clear();
    a->l=u->l;a->r=u->l+k-2;a->ls=u->ls;a->fa=u;if(u->ls!=__) u->ls->fa=a;u->ls=a;
    b->l=u->l+k;b->r=u->r;b->rs=u->rs;b->fa=u;if(u->rs!=__) u->rs->fa=b;u->rs=b;
    u->l=u->r=u->l+k-1;update(a);update(b);update(u);rt[num]=u;
    return u;
}
inline void fill(node* u,node* v)
{
    u->ls=v->ls;u->rs=v->rs;u->fa=v->fa;
    u->l=v->l;u->r=v->r;u->size=v->size;
}
int main()
{
    n=read();m=read();q=read();
    for(register int i=1;i<=n;i++)
    {
        rt[i]=&pool[cnt++];rt[i]->clear();
        rt[i]->l=1ll*(i-1)*m+1;rt[i]->r=1ll*i*m-1;
        rt[i]->size=m-1;
    }
    for(register int i=1;i<=n;i++) insert(rt[n+1],1ll*m*i);
    register int x,y;
    for(register int i=1;i<=q;i++)
    {
        x=read();y=read();
        if(y==m){
            register node* u=find(rt[n+1],x,n+1);
            printf("%lld\n",ans);
            Del(u,n+1);insert(rt[n+1],NOW);
        }
        else{
            register int k=y;
            register node *u=find(rt[x],k,x);
            printf("%lld\n",ans);
            u=split(u,k,x);
            Del(u,x);insert(rt[n+1],NOW);k=x;
            register node* U=find(rt[n+1],k,n+1);
            Del(U,n+1);insert(rt[x],NOW);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/element_hero/article/details/80290118
今日推荐