1. 程式人生 > >NOIP2017 列隊

NOIP2017 列隊

vector n-1 reg 前言 esp ++ code pla 暴力

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 列隊