JZOJ 5478. 【NOIP2017提高组正式赛】列队
Description
Sylvia 是一個(gè)熱愛學(xué)習(xí)的女孩子。前段時(shí)間,Sylvia 參加了學(xué)校的軍訓(xùn)。眾所周知,軍訓(xùn)的時(shí)候需要站方陣。 Sylvia所在的方陣中有n × m名學(xué)生,方陣的行數(shù)為 n,列數(shù)為 m。為了便于管理,教官在訓(xùn)練開始時(shí),按照從前到后,從左到右的順序給方陣中從 1 到 n × m 編上了號(hào)碼(參見后面的樣例)。即:初始時(shí),第 i 行第 j 列的學(xué)生的編號(hào)是(i ? 1) × m + j。然而在練習(xí)方陣的時(shí)候,經(jīng)常會(huì)有學(xué)生因?yàn)楦鞣N各樣的事情需要離隊(duì)。在一天中,一共發(fā)生了 q 件這樣的離隊(duì)事件。每一次離隊(duì)事件可以用數(shù)對(duì)(y,z) (1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的學(xué)生離隊(duì)。在有學(xué)生離隊(duì)后,隊(duì)伍中出現(xiàn)了一個(gè)空位。為了隊(duì)伍的整齊,教官會(huì)依次下達(dá)這樣的兩條指令:1. 向左看齊。這時(shí)第一列保持不動(dòng),所有學(xué)生向左填補(bǔ)空缺。不難發(fā)現(xiàn)在這條指令之后,空位在第 x 行第 m 列。2. 向前看齊。這時(shí)第一行保持不動(dòng),所有學(xué)生向前填補(bǔ)空缺。不難發(fā)現(xiàn)在這條指令之后,空位在第 n 行第 m 列。教官規(guī)定不能有兩個(gè)或更多學(xué)生同時(shí)離隊(duì)。即在前一個(gè)離隊(duì)的學(xué)生歸隊(duì)之后,下一個(gè)學(xué)生才能離隊(duì)。因此在每一個(gè)離隊(duì)的學(xué)生要?dú)w隊(duì)時(shí),隊(duì)伍中有且僅有第 n 行第 m 列一個(gè)空位,這時(shí)這個(gè)學(xué)生會(huì)自然地填補(bǔ)到這個(gè)位置。因?yàn)檎痉疥囌娴暮軣o聊,所以 Sylvia 想要計(jì)算每一次離隊(duì)事件中,離隊(duì)的同學(xué)的編號(hào)是多少。注意:每一個(gè)同學(xué)的編號(hào)不會(huì)隨著離隊(duì)事件的發(fā)生而改變,在發(fā)生離隊(duì)事件后方陣中同學(xué)的編號(hào)可能是亂序的。Input
輸入共 q+1 行。 第 1 行包含 3 個(gè)用空格分隔的正整數(shù) n, m, q,表示方陣大小是 n 行 m 列,一共發(fā)生了 q 次事件。 接下來 q 行按照事件發(fā)生順序描述了 q 件事件。每一行是兩個(gè)整數(shù) x, y,用一個(gè)空格分隔,表示這個(gè)離隊(duì)事件中離隊(duì)的學(xué)生當(dāng)時(shí)排在第 x 行第 y 列。Output
按照事件輸入的順序,每一個(gè)事件輸出一行一個(gè)整數(shù),表示這個(gè)離隊(duì)事件中離隊(duì)學(xué)生的編號(hào)Sample Input
【輸入樣例 1】
2 2 3
1 1
2 2
1 2
Sample Output
【輸出樣例 1】
1
1
4
【輸入輸出樣例 1 說明】
列隊(duì)的過程如上圖所示,每一行描述了一個(gè)事件。
在第一個(gè)事件中,編號(hào)為 1 的同學(xué)離隊(duì),這時(shí)空位在第一行第一列。接著所有同學(xué)向左標(biāo)齊,這時(shí)編號(hào)為 2 的同學(xué)向左移動(dòng)一步,空位移動(dòng)到第一行第二列。然后所有同學(xué)向上標(biāo)齊,這時(shí)編號(hào)為 4 的同學(xué)向上一步,這時(shí)空位移動(dòng)到第二行第二列。最后編號(hào)為 1 的同學(xué)返回填補(bǔ)到空位中。
Data Constraint
Solution
對(duì)于每一個(gè)操作 (x,y) , 相當(dāng)于把第 x 行 y+1 列到 m 列左移,
再把第 m 列第 x+1 行到第 n 行上移,把 (x,y) 移到 (n,m) 。
如果每一行只看前 m?1 列的數(shù),第 m 列單獨(dú)看 1?n 行的數(shù)。
那么問題可以轉(zhuǎn)換為一種查詢兩種操作:
找到第 k 大的數(shù)并把它刪掉;
加一個(gè)數(shù)在序列后面。
注意到加入只是加入到 序列的末尾,且加入數(shù)≤300000 ,
所以可以用線段樹預(yù)留 300000 位置直接維護(hù),查詢用 線段樹二分。
但是空間限制不允許把所有的東西存下來,所以用 動(dòng)態(tài)開節(jié)點(diǎn) 的方法來維護(hù)線段樹。
動(dòng)態(tài)開節(jié)點(diǎn)也有可能爆空間(甚至是時(shí)間),所以可以預(yù)先求出每一行要開的大小,
這樣就不用開到 600000 ,均攤下來還是 300000 。
時(shí)間復(fù)雜度 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; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5478. 【NOIP2017提高组正式赛】列队的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5477. 【NOIP2017
- 下一篇: JZOJ 3468. 【NOIP2013