洛谷P3960 列隊
洛谷P3960 列隊
題目描述
Sylvia 是一個熱愛學習的女孩子。
前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。
Sylvia 所在的方陣中有\(n \times m\)名學生,方陣的行數為 \(n\),列數為 \(m\)。
為了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中 的學生從 \(1\) 到 \(n \times m\) 編上了號碼(參見後面的樣例)。即:初始時,第 \(i\) 行第 \(j\) 列 的學生的編號是\((i-1)\times m + j\)。
然而在練習方陣的時候,經常會有學生因為各種各樣的事情需要離隊。在一天 中,一共發生了 $q \(件這樣的離隊事件。每一次離隊事件可以用數對\)
在有學生離隊後,隊伍中出現了一個空位。為了隊伍的整齊,教官會依次下達 這樣的兩條指令:
- 向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條 指令之後,空位在第 \(x\) 行第 \(m\) 列。
- 向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條 指令之後,空位在第 \(n\) 行第 \(m\) 列。
教官規定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之後, 下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第 \(n\)
因為站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學的編號是多少。
註意:每一個同學的編號不會隨著離隊事件的發生而改變,在發生離隊事件後方陣中同學的編號可能是亂序的。
輸入輸出格式
輸入格式:
輸入共 \(q+1\) 行。
第 1 行包含 3 個用空格分隔的正整數 \(n, m, q\),表示方陣大小是 \(n\) 行 \(m\) 列,一共發 生了 \(q\) 次事件。
接下來 \(q\) 行按照事件發生順序描述了 \(q\) 件事件。每一行是兩個整數 \(x, y\),用一個空 格分隔,表示這個離隊事件中離隊的學生當時排在第 \(x\)
輸出格式:
按照事件輸入的順序,每一個事件輸出一行一個整數,表示這個離隊事件中離隊學生的編號。
思路
可以發現每一次離隊只會影響離隊者所在的這一排和最後一列
於是我們建立\(n+1\)棵線段樹,前\(n\)棵維護每一行的前\(m-1\)列,最後一棵維護最後一列。
每一棵線段樹維護區間和。
由於最多會進行\(q\)次操作,因此每一行最多會進行\(q\)次更新,故線段樹只需要開到\(m+q\),如果使用動態開點的話是可以維護的。
對於每一次離隊操作,如果在前\(m-1\)列,那麽將這一次離隊者在線段樹中的位置的值設為\(0\),然後將第\(n+1\)棵線段樹中這一行對應的位置的值設為\(0\),並將它添加到離隊者原來所在的線段樹的末尾,然後將離隊者插入第\(m+1\)棵線段樹的末尾。
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 10000010
typedef long long int lli;
int ch[MAXN][2],sz[MAXN],rt[MAXN],nums[MAXN];
lli val[MAXN];
int i,j,k,m,n,x,y,ncnt,maxn;
char readc;
void read(int &n){
while((readc=getchar())<48||readc>57);
n=readc-48;
while((readc=getchar())>=48&&readc<=57) n=n*10+readc-48;
}
int getsize(int id,int l,int r){
if(id<=n){
if(r<m) return r-l+1;
if(l<m) return m-l;
return 0;
}
if(r<=n) return r-l+1;
if(l<=n) return n-l+1;
return 0;
}
void update(int id,int &rt,int l,int r,int p,lli upd){
if(!rt){
rt=++ncnt;
ch[rt][0]=ch[rt][1]=0;
sz[rt]=getsize(id,l,r);
if(l==r) val[rt]=upd;
}
sz[rt]++;
if(l==r){
return;
}
int mid=(l+r)>>1;
if(p<=mid) update(id,ch[rt][0],l,mid,p,upd);
else update(id,ch[rt][1],mid+1,r,p,upd);
}
lli query(int id,int &rt,int l,int r,int p){
if(!rt){
rt=++ncnt;
ch[rt][0]=ch[rt][1]=0;
sz[rt]=getsize(id,l,r);
if(l==r){
if(id<=n){
val[rt]=(lli) (id-1)*m+l;
}else val[rt]=(lli) l*m;
}
}
sz[rt]--;
if(l==r) {
return val[rt];
}
int mid=(l+r)>>1;
if(ch[rt][0]){
if(p<=sz[ch[rt][0]]){
return query(id,ch[rt][0],l,mid,p);
}else{
return query(id,ch[rt][1],mid+1,r,p-sz[ch[rt][0]]);
}
}else{
if(p<=mid-l+1){
return query(id,ch[rt][0],l,mid,p);
}else{
return query(id,ch[rt][1],mid+1,r,p-(mid-l+1));
}
}
return 0;
}
int main(){
read(n),read(m),read(k);
ncnt=0;
for(i=1;i<=n;i++) nums[i]=m-1;
nums[n+1]=n;
maxn=max(n,m)+k;
for(i=1;i<=k;i++){
read(x),read(y);
lli tmp;
if(y<m){
tmp=query(x,rt[x],1,maxn,y);
update(n+1,rt[n+1],1,maxn,++nums[n+1],tmp);
printf("%lld\n",tmp);
tmp=query(n+1,rt[n+1],1,maxn,x);
update(x,rt[x],1,maxn,++nums[x],tmp);
}else{
tmp=query(n+1,rt[n+1],1,maxn,x);
update(n+1,rt[n+1],1,maxn,++nums[n+1],tmp);
printf("%lld\n",tmp);
}
}
return 0;
}
洛谷P3960 列隊