Description
最近小M買了一個移動硬盤來儲存自己電腦裏不常用的文件。但是他把這些文件一股腦丟進移動硬盤後,覺得這些文件似乎沒有被很好地歸類,這樣以後找起來豈不是會非常麻煩?
小M最終決定要把這些文件好好歸類,把同一類地移動到一起。所以現在小M有了這幾種操作:
1 u 表示把編號爲u的文件放到最上面
2 u 表示把編號爲u的文件放到最下面
3 u v 表示把編號爲u的文件放到編號爲v的文件的後面
已知在最開始的時候,1號文件到n號文件從上往下排布
現在小M已經給出了他所進行的所有操作,你能告訴他操作之後的序列是會變成什麼樣子嗎?
Input
第一行爲一個數字T(T<=10)表示數據組數
第二行爲兩個數字n、m(1<=n,m<=300000)表示序列長度和小M的操作次數
接下來m行每行兩個或三個數字,具體含義見題面
保證數據合法
Output
輸出一行表示小M操作結束後的序列
Sample Input
1
10 5
1 5
2 3
2 6
3 4 8
3 1 3
Sample Output
5 2 7 8 4 9 10 3 1 6
Notes
這題我是用靜態鏈表做的,如果用鏈表的話,大量的時間用來尋找編號了,用數組也是這樣,浪費了大量的時間,而題目的數據量也比較大,交上去肯定會超時,這裏面還有一個小技巧就是設置頭節點和尾節點,這樣的話就統一了插入和刪除節點的操作。提高了程序的效率。
AC Code
#include<iostream>
#include<cmath>
#include<cstring>
//#include<vector>
//#include<list>
//#include<stack>
//#include<queue>
#include<map>
//#include<set>
//#include<cstdio>
//#include<cstdlib>
//#include<algorithm>
using namespace std;
typedef long long ll;
const double PI = acos(-1);
const double EPS = 1e-6;
const int INF = 0x3f3f3f3f;
const int MAXN = 3e5 + 10;
struct Node{
int number; //節點編號
int prior; //節點的前驅節點編號
int next; //節點的後繼節點編號
}a[MAXN];
int main(){
freopen("C:\\Users\\Ambition\\Desktop\\in.txt","r",stdin);
int t, n, m, u, v, type;
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
a[0].number=0, a[0].prior=0, a[0].next=1;
for(int i=1; i<=n; ++i){
a[i].number=i, a[i].prior=i-1, a[i].next=i+1;
}
a[n+1].number=n+1, a[n+1].prior=n, a[n+1].next=n+1;
while(m--){
scanf("%d %d", &type, &u);
//摘下u節點
a[a[u].prior].next=a[u].next;
a[a[u].next].prior=a[u].prior;
switch(type){
case 1:
a[u].next=a[0].next;
a[u].prior=0;
a[a[0].next].prior=u;
a[0].next=u;
break;
case 2:
a[u].next=n+1;
a[u].prior=a[n+1].prior;
a[a[n+1].prior].next=u;
a[n+1].prior=u;
break;
case 3:
scanf("%d", &v);
a[u].prior=v;
a[u].next=a[v].next;
a[a[v].next].prior=u;
a[v].next=u;
break;
}
}
int num=a[0].next;
for(int i=0; i<n; ++i){
printf("%d ", a[num].number);
num=a[num].next;
}
printf("\n");
}
return 0;
}