題目
Description
給出 n 條平行的縱向軌道 ,有 m 根橫向的短棒支在一些相鄰軌道上。如果在某個軌道頂端釋放一個小球,它會沿着這個軌道一直下落,一旦碰到短棒就會沿着短棒滾到相鄰軌道並繼續下落。
爲了增加難度,每次可能會拿走某些短棒,或者詢問一個從 x 號軌道下落的小球最終落到哪個軌道。
Input
第一行讀入兩個整數 n,m (2≤n≤5×105,0≤m≤5×105),分別表示軌道的數量和短棒的數量。 第二行讀入 m 個整數,第 i 個整數記爲 idi (1≤idi<n) ,表示從上到下第 i 根短棒位於編號爲 idi 和 idi+1 的軌道之間。 第三行讀入一個整數 Q (1≤Q≤5×105),表示操作總數。 接下來讀入 Q 行,每行讀入兩個整數 opt,x。如果 opt=1,表示拿走從上到下的第 x (1≤x≤m) 根短棒。保證不會拿走重複的木棒。如果 opt=2,詢問一個初始從軌道 x (1≤x≤n) 下落的小球最終落到了哪個軌道。
Output
對於每一個 opt=2 的操作,輸出最終到達的軌道編號。
Sample Input
6 5
2 1 5 3 2
10
2 1
2 2
2 6
1 3
2 6
2 3
1 1
2 2
2 3
2 4
Sample Output
3
4
5
6
1
1
4
2
Hint
一共有 10 組測試數據,數據有梯度。
測試點編號 特殊性質
1,2,3 m,Q≤1000
4,5 沒有拿走短棒的操作
6,7 n,m,Q≤50000
8 n=m=Q=100000,初始短棒位置、拿走的短棒、詢問的軌道都在其可行範圍內均勻隨機
9,10 無特殊約定
思路
測試點 1,2,3
每次詢問時從高到低枚舉每一根短棒,如果在一側就變成另一側。 效率: 。注意可能會很大。
測試點 4,5
因爲沒有修改,可以考慮提前算出所有的答案。 一開始設 ,從低到高觀察每一根木棒:如果它位於 之間,相當於交換 和 的值。預處理完後就可以直接輸出答案了。
效率
代碼
#include<bits/stdc++.h>
using namespace std;
const int N=4e6+77;
int s[N][2],f[N],a[N],yjy[N],n,m,cnt;
void rotate(int x){
int y=f[x],z=f[y],w=s[y][0]==x;
if (s[y][w^1]=s[x][w]) f[s[x][w]]=y;
if (z) s[z][s[z][1]==y]=x;
s[x][w]=y;f[y]=x;f[x]=z;
}
void splay(int x){
while (f[x]){
int y=f[x],z=f[y];
if (z)
rotate(((s[z][1]==y)^(s[y][1]==x))?x:y);
rotate(x);
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d",&a[i]);
cnt=1;
for (int i=m;i;i--){
++cnt;
if (f[cnt]=yjy[a[i]])
s[yjy[a[i]]][1]=cnt;
yjy[a[i]]=cnt^1;
++cnt;
if (f[cnt]=yjy[a[i]+1])
s[yjy[a[i]+1]][1]=cnt;
yjy[a[i]+1]=cnt^1;
}
for (int i=1;i<=n;i++){
++cnt;
if (f[cnt]=yjy[i])
s[yjy[i]][1]=cnt;
}
int Q;
scanf("%d",&Q);
while (Q--){
int T,x;
scanf("%d%d",&T,&x);
if (T==1){
int p=(m-x+1)*2,q=p+1;
splay(p);splay(q);
if (s[p][1]) f[s[p][1]]=q;
if (s[q][1]) f[s[q][1]]=p;
swap(s[p][1],s[q][1]);
}
else {
x+=2*m+1;
splay(x);
int ret=x;
for (;s[ret][0];ret=s[ret][0]);
printf("%d\n",ret<=2*m+1?a[m-ret/2+1]+(ret&1):x-2*m-1);
}
}
}