JZOJ 5478. 【NOIP2017提高组正式赛】列队
生活随笔
收集整理的這篇文章主要介紹了
JZOJ 5478. 【NOIP2017提高组正式赛】列队
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
Sylvia 是一個熱愛學習的女孩子。前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。 Sylvia所在的方陣中有n × m名學生,方陣的行數為 n,列數為 m。為了便于管理,教官在訓練開始時,按照從前到后,從左到右的順序給方陣中從 1 到 n × m 編上了號碼(參見后面的樣例)。即:初始時,第 i 行第 j 列的學生的編號是(i ? 1) × m + j。然而在練習方陣的時候,經常會有學生因為各種各樣的事情需要離隊。在一天中,一共發生了 q 件這樣的離隊事件。每一次離隊事件可以用數對(y,z) (1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的學生離隊。在有學生離隊后,隊伍中出現了一個空位。為了隊伍的整齊,教官會依次下達這樣的兩條指令:1. 向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條指令之后,空位在第 x 行第 m 列。2. 向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條指令之后,空位在第 n 行第 m 列。教官規定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之后,下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第 n 行第 m 列一個空位,這時這個學生會自然地填補到這個位置。因為站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學的編號是多少。注意:每一個同學的編號不會隨著離隊事件的發生而改變,在發生離隊事件后方陣中同學的編號可能是亂序的。Input
輸入共 q+1 行。 第 1 行包含 3 個用空格分隔的正整數 n, m, q,表示方陣大小是 n 行 m 列,一共發生了 q 次事件。 接下來 q 行按照事件發生順序描述了 q 件事件。每一行是兩個整數 x, y,用一個空格分隔,表示這個離隊事件中離隊的學生當時排在第 x 行第 y 列。Output
按照事件輸入的順序,每一個事件輸出一行一個整數,表示這個離隊事件中離隊學生的編號Sample Input
【輸入樣例 1】
2 2 3
1 1
2 2
1 2
Sample Output
【輸出樣例 1】
1
1
4
【輸入輸出樣例 1 說明】
列隊的過程如上圖所示,每一行描述了一個事件。
在第一個事件中,編號為 1 的同學離隊,這時空位在第一行第一列。接著所有同學向左標齊,這時編號為 2 的同學向左移動一步,空位移動到第一行第二列。然后所有同學向上標齊,這時編號為 4 的同學向上一步,這時空位移動到第二行第二列。最后編號為 1 的同學返回填補到空位中。
Data Constraint
Solution
對于每一個操作 (x,y) , 相當于把第 x 行 y+1 列到 m 列左移,
再把第 m 列第 x+1 行到第 n 行上移,把 (x,y) 移到 (n,m) 。
如果每一行只看前 m?1 列的數,第 m 列單獨看 1?n 行的數。
那么問題可以轉換為一種查詢兩種操作:
找到第 k 大的數并把它刪掉;
加一個數在序列后面。
注意到加入只是加入到 序列的末尾,且加入數≤300000 ,
所以可以用線段樹預留 300000 位置直接維護,查詢用 線段樹二分。
但是空間限制不允許把所有的東西存下來,所以用 動態開節點 的方法來維護線段樹。
動態開節點也有可能爆空間(甚至是時間),所以可以預先求出每一行要開的大小,
這樣就不用開到 600000 ,均攤下來還是 300000 。
時間復雜度 O(Q?log(N+Q)) 。
Code
#include<cstdio> #include<cctype> using namespace std; typedef long long LL; const int N=6e6+5; int tot,pos; int size[N],s[N][2],len[N],rt[N]; LL key[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } inline void write(LL x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline void update(int v) {size[v]=size[s[v][0]]+size[s[v][1]]; } inline LL kth(int &v,int l,int r,int x) {if(!v) v=++tot;if(l==r){size[v]=1,pos=l;return key[v];}int mid=l+r>>1,wz=mid-l+1-size[s[v][0]];LL y=wz>=x?kth(s[v][0],l,mid,x):kth(s[v][1],mid+1,r,x-wz);update(v);return y; } inline void change(int &v,int l,int r,int x,LL y) {if(!v) v=++tot;if(l==r){key[v]=y;return;}int mid=l+r>>1;if(x<=mid) change(s[v][0],l,mid,x,y); else change(s[v][1],mid+1,r,x,y);update(v); } int main() {int n=read(),m=read(),q=read();for(int i=1;i<=n;i++) len[i]=m-1;len[n+1]=n;for(int i=1;i<=q;i++){int x=read(),y=read();if(y==m){LL num=kth(rt[n+1],1,n+q,x);if(pos<=n) num=(LL)pos*m;write(num),putchar('\n');change(rt[n+1],1,n+q,++len[n+1],num);}else{LL num=kth(rt[x],1,m+q,y);if(pos<m) num=(LL)(x-1)*m+pos;write(num),putchar('\n');change(rt[n+1],1,n+q,++len[n+1],num);num=kth(rt[n+1],1,n+q,x);if(pos<=n) num=(LL)pos*m;change(rt[x],1,m+q,++len[x],num);}}return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5478. 【NOIP2017提高组正式赛】列队的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5477. 【NOIP2017
- 下一篇: JZOJ 3468. 【NOIP2013