NOIP2017 列队

Posted guessycb

tags:

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

NOIP2017 列队

题目大意

有一个\(n*m\)的列队方格。
一开始,这个列队中\((i,j)\)的人的编号为\((i-1)m+j\)
每次下达一个指令\((x,y)\),使得\((x,y)\)这个位置的人出列。
然后:

  • 向左看齐,所有人向左填补空位。
  • 向前看齐,所有人向前填补空位。

不难发现两次看齐后空位变到了\((n,m)\),然后令刚才出列的人回到这个位置。
对于依次进行的\(Q\)次指令,你需要输出出列的人的编号。
数据范围:\(n,m,Q \leq 3*10^5\)

前言

NOIP此题50分选手现在依旧觉得:好神啊这题(QwQ)。
我自己的想法是:
对于每一行和最后一列维护一个\(Splay\),把连续的整块看做一个点。
每次先二分找到对应的整块,然后把整块分开再重新插入\(Splay\),一直做下去即可。
超级暴力的\(Splay\)直接硬上......
我发现自己写不出来,瑟瑟发抖......(后来发现ZSY和YYB写的就是这个,太强了ORZ!)
所以比较好写的做法是:

题解

依旧顺着上面说的那种做法,
修改\((x,y)\)影响的只有第\(x\)行和第\(m\)列。
那么我们开\(n\)棵 线段木(动态开点) 来维护每行的前\(m-1\)列,再开一棵维护最后一列。
可以发现初始每一棵线段木中存的元素是连续的一段。
所以我们用线段木维护初始每一行的元素,每次二分查找看答案是不是初始元素。
如果是初始元素那么直接输出就行了。
如果不是呢?
我们开\(vector\)记录每一行和最后一列中后来加入的元素
如果不是直接到\(vector\)中取即可。
这题就做完了,线段木写起来真的非常的舒服(QwQ)。

实现代码

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 300005
using namespace std;

IL int gi(){
    RG int data = 0 , m = 1; RG char ch = 0;
    while(ch != '-' && (ch<'0' || ch > '9')) ch = getchar();
    if(ch == '-'){m = 0; ch = getchar();}
    while(ch>='0' && ch<='9'){data = (data<<1) + (data<<3) + ch - '0' ;  ch = getchar();}
    return (m) ? data : -data ; 
}

struct Segment_Tree{int ls,rs,sz;}t[60*_]; 
int n,m,f[_],rt[_],tot,Lg,Q; vector<long long>vec[_] ; 

int Query(RG int o,RG int l,RG int r,RG int K){
    if(l == r) return l ; 
    RG int mid = (l + r) >> 1 , SZ = (mid-l+1) - t[t[o].ls].sz ; 
    if(K <= SZ) return Query(t[o].ls , l , mid , K) ; 
    else if(K > SZ) return Query(t[o].rs , mid + 1 , r , K - SZ) ; 
}
void Delete(RG int &o,RG int l,RG int r,RG int p){
    if(!o)o = ++tot ; 
    ++ t[o].sz; if(l == r)return ; 
    RG int mid = (l + r) >> 1;
    if(p <= mid) Delete(t[o].ls , l , mid , p) ; 
    else if(p > mid) Delete(t[o].rs , mid + 1 , r , p) ; 
}

IL long long Delete_line(RG int x,RG int kth){
    RG int id = Query(rt[x] , 1 , Lg , kth) ; 
    Delete(rt[x] , 1 , Lg , id) ;  
    return (id <= m-1) ? 1ll * (x-1) * m + id : vec[x][id-m]; 
}
IL long long Delete_row(RG int kth){
    RG int id = Query(rt[n+1] , 1 , Lg , kth) ; 
    Delete(rt[n+1] , 1 , Lg , id) ;  
    return (id <= n) ? 1ll * id * m : vec[n+1][id-n-1]; 
}

int main(){
    n = gi(); m = gi(); Q = gi();
    Lg = max(n , m) + Q + 1;
    long long id , id2 ; 
    while(Q --){
        RG int x = gi() , y = gi() ; 
        if(y ^ m){
            id = Delete_line(x , y) ;  id2 = Delete_row(x) ;
            vec[x].push_back(id2) ;   vec[n+1].push_back(id) ; 
        }
        else{
            id = Delete_row(x) ; 
            vec[n+1].push_back(id) ; 
        }
        printf("%lld\n" , id) ; 
    }return 0;
} 

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

NOIP2017列队(phalanx)解题报告

[NOIp 2017]列队

NOIP2017D2T3 列队—Treap

[NOIP2017]列队

[jzoj]5478.NOIP2017提高组正式赛列队

[NOIP2017D2T3]列队