題目
描述
Sylvia 是一個熱愛學習的女♂孩子。
前段時間,Sylvia 參加了學校的軍訓。衆所周知,軍訓的時候需要站方陣。
Sylvia 所在的方陣中有 名學生,方陣的行數爲 ,列數爲 。
爲了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中 的學生從 1 到 編上了號碼(參見後面的樣例)。即:初始時,第 行第 列 的學生的編號是 。
然而在練習方陣的時候,經常會有學生因爲各種各樣的事情需要離隊。在一天 中,一共發生了 件這樣的離隊事件。每一次離隊事件可以用數對 描述,表示第 行第 列的學生離隊。
在有學生離隊後,隊伍中出現了一個空位。爲了隊伍的整齊,教官會依次下達 這樣的兩條指令:
- 向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條 指令之後,空位在第 行第 列。
- 向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條 指令之後,空位在第 行第 列。
教官規定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之後, 下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第 行 第 列一個空位,這時這個學生會自然地填補到這個位置。
因爲站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學 的編號是多少。
注意:每一個同學的編號不會隨着離隊事件的發生而改變,在發生離隊事件後 方陣中同學的編號可能是亂序的。
輸入
輸入共 行。
第 1 行包含 3 個用空格分隔的正整數 ,表示方陣大小是 行 列,一共發 生了 次事件。
接下來 行按照事件發生順序描述了 件事件。每一行是兩個整數 ,用一個空 格分隔,表示這個離隊事件中離隊的學生當時排在第 行第 列。
輸出
按照事件輸入的順序,每一個事件輸出一行一個整數,表示這個離隊事件中離隊學 生的編號。
輸入樣例
2 2 3
1 1
2 2
1 2
輸出樣例
1
1
4
數據規模與約定
數據保證每一個事件滿足
解題思路
一道數據結構的好題。
首先我們發現,每次操作只會更改某一行和最後一列的狀態,那麼我們可以單獨把最後一列拿出來用一個數據結構維護,再用 個數據結構維護每一行的前 個元素。
那用什麼數據結構好呢?
一、線段樹
線段樹是最容易想到的,共開 顆線段樹,前 顆維護每行前 個元素,第 顆維護最後一列的元素。
每次對 操作都可以轉化爲一個基本操作:從一顆線段樹裏面拿出一個元素加到一顆線段樹的末尾,具體來說:
- 如果 ,只需要從“列線段樹”裏拿出第 個元素加到它本身末尾
- 否則,從第 顆“行線段樹”裏拿出第 個元素加到“列線段樹”末尾,再從“列線段樹”裏拿出第 個元素加到“行線段樹”末尾
所謂的“拿出”操作就是一個在線段樹上二分查找的過程,爲此我們要在線段樹每個節點上記錄一個size,表示當前節點表示的區間裏面還剩多少個元素。
另外,每顆線段樹要多開 的區間長度(想想操作過程就明白了)。
但是,以上並不是這道題的難點,這道題的特殊之處在於你無法直接開滿 顆線段樹!
怎麼辦呢,我們可以動態開點來解決,也就是說當你要用某個點時再開它(想想主席樹)。這樣我們只需要 的空間就夠了。
時間複雜度
二、平衡樹
既然線段樹可以,平衡樹當然也可以了!
同樣的思路:每次操作都可以轉化爲從一顆平衡樹上二分查找第k大的值,把它加到一顆平衡樹的末尾。
怎麼解決空間問題?由於有一些人至始至終都站在一起,我們可以在平衡樹上只用一個節點表示這個區間 (編號從 到 的人),當我們發現這個區間中的某個人(如編號爲 的人)要離隊時,再把它split成兩個小區間( ),輸出 ,這樣就能保證空間複雜度爲 。
時間複雜度
三、樹狀數組
有待學習…
Code#1(線段樹)
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 300005;
int n, m, q, qx, qy, p[N], root[N];
LL t;
struct segTree{
int son[2];
LL val, size;
}tr[N*30];
struct OPT_segTree{
int cnt;
inline int newNode(int l, int r, int kind){
cnt++;
int temp = (kind == 0 ? m - 1 : n);
if(l <= temp && r <= temp) tr[cnt].size = r - l + 1;
else if(l <= temp && r > temp) tr[cnt].size = temp - l + 1;
else if(l > temp && r > temp) tr[cnt].size = 0;
return cnt;
}
inline void pushup(int id){
tr[id].size = tr[tr[id].son[0]].size + tr[tr[id].son[1]].size;
}
LL getKth(int id, int l, int r, LL k, int kind){
if(l == r){
if(!tr[id].val){
if(kind == 0) tr[id].val = 1ll * (qx - 1) * m + l;
else tr[id].val = 1ll * l * m;
}
tr[id].size = 0;
return tr[id].val;
}
int mid = (l + r) >> 1;
if(!tr[id].son[0]) tr[id].son[0] = newNode(l, mid, kind);
if(!tr[id].son[1]) tr[id].son[1] = newNode(mid+1, r, kind);
LL res = 0;
if(tr[tr[id].son[0]].size >= k) res = getKth(tr[id].son[0], l, mid, k, kind);
else res = getKth(tr[id].son[1], mid+1, r, k - tr[tr[id].son[0]].size, kind);
pushup(id);
return res;
}
void insert(int id, int l, int r, int pos, LL val, int kind){
if(l == r){
tr[id].val = val;
tr[id].size = 1;
return;
}
int mid = (l + r) >> 1;
if(!tr[id].son[0]) tr[id].son[0] = newNode(l, mid, kind);
if(!tr[id].son[1]) tr[id].son[1] = newNode(mid+1, r, kind);
if(pos <= mid) insert(tr[id].son[0], l, mid, pos, val, kind);
else insert(tr[id].son[1], mid+1, r, pos, val, kind);
pushup(id);
}
}Seg;
int main(){
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i++) p[i] = m - 1;
p[n+1] = n;
for(int i = 1; i <= n; i++) root[i] = Seg.newNode(1, m - 1 + q, 0);
root[n+1] = Seg.newNode(1, n + q, 1);
for(int i = 1; i <= q; i++){
scanf("%d%d", &qx, &qy);
if(qy == m){
printf("%lld\n", t = Seg.getKth(root[n+1], 1, n + q, qx, 1));
Seg.insert(root[n+1], 1, n + q, ++p[n+1], t, 1);
}
else{
printf("%lld\n", t = Seg.getKth(root[qx], 1, m - 1 + q, qy, 0));
Seg.insert(root[n+1], 1, n + q, ++p[n+1], t, 1);
t = Seg.getKth(root[n+1], 1, n + q, qx, 1);
Seg.insert(root[qx], 1, m - 1 + q, ++p[qx], t, 0);
}
}
return 0;
}
Code#2(Splay)
#include<cstdio>
using namespace std;
typedef long long LL;
const int N = 300005;
int qx, qy, rt[N];
LL t, n, m, q;
struct Splay{
int son[2], fa;
LL val, l, r, size;
}tr[N*30];
struct OPT_Splay{
int cnt;
inline void pushup(int id){
tr[id].size = tr[id].r - tr[id].l + 1;
if(tr[id].son[0]) tr[id].size += tr[tr[id].son[0]].size;
if(tr[id].son[1]) tr[id].size += tr[tr[id].son[1]].size;
}
inline int newNode(LL l, LL r){
cnt++;
tr[cnt].fa = tr[cnt].son[0] = tr[cnt].son[1] = 0;
tr[cnt].size = (tr[cnt].r = r) - (tr[cnt].l = l) + 1;
return cnt;
}
inline void rotate(int x, int kind){
int y = tr[x].fa, z = tr[y].fa, A = tr[y].son[kind], B = tr[x].son[kind], C = tr[x].son[!kind];
tr[x].son[kind] = y, tr[x].fa = z;
tr[y].fa = x, tr[y].son[!kind] = B;
tr[z].son[tr[z].son[1] == y] = x, tr[B].fa = y;
pushup(y), pushup(x);
}
inline void splay(int &root, int x, int goal){
if(x == goal) return;
while(tr[x].fa != goal){
int y = tr[x].fa, z = tr[y].fa;
int isrson1 = tr[y].son[1] == x, isrson2 = tr[z].son[1] == y;
if(z == goal) rotate(x, !isrson1);
else{
if(isrson1 == isrson2) rotate(y, !isrson2);
else rotate(x, !isrson1);
rotate(x, !isrson2);
}
}
if(goal == 0) root = x;
}
inline int selectLast(int &root){
int now = root;
while(tr[now].son[1]) now = tr[now].son[1];
return now;
}
inline void insert(int &root, LL val){
int temp = newNode(val, val);
int pos = selectLast(root);
tr[pos].son[1] = temp;
tr[temp].fa = pos;
splay(root, temp, 0);
}
LL split(int &root, int now, LL k){
splay(root, now, 0);
k += tr[now].l - 1;
int temp = newNode(k+1, tr[now].r);
tr[now].r = k - 1;
if(!tr[now].son[1]){
tr[now].son[1] = temp;
tr[temp].fa = now;
}
else{
tr[temp].son[1] = tr[now].son[1];
tr[tr[temp].son[1]].fa = temp;
tr[now].son[1] = temp;
tr[temp].fa = now;
}
pushup(temp), pushup(now);
return k;
}
inline LL getKth(int &root, LL k){
int now = root;
while(1){
if(k <= tr[tr[now].son[0]].size) now = tr[now].son[0];
else{
k -= tr[tr[now].son[0]].size;
if(k <= tr[now].r - tr[now].l + 1)
return split(root, now, k);
else{
k -= (tr[now].r - tr[now].l + 1);
now = tr[now].son[1];
}
}
}
}
}BST;
int main(){
scanf("%lld%lld%lld", &n, &m, &q);
for(int i = 1; i <= n; i++) rt[i] = BST.newNode((i - 1) * m + 1, i * m - 1);
rt[n+1] = BST.newNode(m, m);
for(int i = 2; i <= n; i++) BST.insert(rt[n+1], i * m);
while(q--){
scanf("%d%d", &qx, &qy);
if(qy == m){
printf("%lld\n", t = BST.getKth(rt[n+1], qx));
BST.insert(rt[n+1], t);
}
else{
printf("%lld\n", t = BST.getKth(rt[qx], qy));
BST.insert(rt[n+1], t);
BST.insert(rt[qx], BST.getKth(rt[n+1], qx));
}
}
return 0;
}