Description
Sylvia 是一個熱愛學習的女孩子。
前段時間,Sylvia 參加了學校的軍訓。衆所周知,軍訓的時候需要站方陣。 Sylvia所在的方陣中有n × m名學生,方陣的行數爲 n,列數爲 m。
爲了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中從 1 到 n × m 編上了號碼(參見後面的樣例)。即:初始時,第 i 行第 j 列的學生的編號是(i − 1) × m + j。
然而在練習方陣的時候,經常會有學生因爲各種各樣的事情需要離隊。在一天中,一共發生了 q 件這樣的離隊事件。每一次離隊事件可以用數對(��,��) (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,表示方陣大小是 �� 行 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
想法:
權值線段樹+線段樹二分+動態開點
線段樹存幾個值:
x:如果區間長度爲1,存當前位置的值
sum:這個區間有多少個數
l,r:左兒子和右兒子
開n+1棵線段樹,前n個存每行的值(m-1+q)
第n+1棵存第m列的值(n+q)
要做的事很簡單:
y!=m時
把第x行第y個的值找到記爲ans並刪除
把第m列第x個找到並刪除,插入第x行最後一個
把ans插入第m列最後一個那裏
y==m更簡單
Code
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
const ll maxN=300010;
ll n,m,q,i,len,lem,cnt,p[maxN],ans,sum,sum1,x1,y2,end[maxN];
struct zhj{
ll x;
int right,left,sum;
};
zhj tree[18000000];
void ef(ll x,ll head,ll tail,ll xx,ll y){
ll mid=(head+tail)/2;
if (head==tail){
if (tree[x].x==0) {
if (xx==n+1) tree[x].x=head*m;else tree[x].x=(xx-1)*m+head;
}
ans=tree[x].x;
tree[x].sum=0;
return;
}
mid=(head+tail)/2;
if (tree[x].left==0){
tree[x].left=++cnt,tree[cnt].sum=mid-head+1;
}
if (tree[x].right==0){
tree[x].right=++cnt,tree[cnt].sum=tail-mid;
}
if (tree[tree[x].left].sum>=y) ef(tree[x].left,head,mid,xx,y);
else ef(tree[x].right,mid+1,tail,xx,y-tree[tree[x].left].sum);
tree[x].sum=tree[tree[x].left].sum+tree[tree[x].right].sum;
}
void find(ll x,ll head,ll tail,ll zl,ll l,ll r,ll y){
if ((l<=head)&&(tail<=r)){
if (zl==0) tree[x].x=y,tree[x].sum=1;
if (zl==1) tree[x].sum=tail-head+1;
return;
}
ll mid=(head+tail)/2;
if (tree[x].left==0){
tree[x].left=++cnt;
}
if (tree[x].right==0){
tree[x].right=++cnt;
}
if (l<=mid) find(tree[x].left,head,mid,zl,l,r,y);
if (mid<r) find(tree[x].right,mid+1,tail,zl,l,r,y);
tree[x].sum=tree[tree[x].left].sum+tree[tree[x].right].sum;
}
int main(){
freopen("phalanx.in","r",stdin);
freopen("phalanx.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&q);
len=m+q-1,lem=n+q;
for (i=1;i<=n;i++)
p[i]=++cnt,tree[cnt].sum=m-1,end[i]=m-1,find(p[i],1,len,1,1,m-1,0);
p[n+1]=++cnt;
tree[cnt].sum=n,end[i]=n,find(p[n+1],1,lem,1,1,n,0);
for (i=1;i<=q;i++){
scanf("%lld%lld",&x1,&y2);
if (y2==m){
ans=0,ef(p[n+1],1,lem,n+1,x1);
printf("%lld\n",ans);
end[n+1]++;
find(p[n+1],1,lem,0,end[n+1],end[n+1],ans);
continue;
}
ans=0,ef(p[x1],1,len,x1,y2),sum=ans;
printf("%lld\n",ans);
ans=0,ef(p[n+1],1,lem,n+1,x1);
end[x1]++;
find(p[x1],1,len,0,end[x1],end[x1],ans);
end[n+1]++;
find(p[n+1],1,lem,0,end[n+1],end[n+1],sum);
}
}