V(1982): 小M的移动硬盘
Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 171 Solved: 66Description
最近小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
应该很明显就可以看出来是对链表的基本操作。只是本人比较懒,创建链表嫌麻烦,c++的STL似乎也没有链表的模板类,所以我用数组模拟了链表,算是用的双链表吧,其实单链表好像也是可以解决的。我用了两个数组分别记录前驱和后继。
#include<iostream>
using namespace std;
int le[300005], ri[300005];//分别放前驱和后继
int m;
//别纠结这个名字为什么会是swap,原谅我英语差
void swap(int x, int y)//双链表将x插入到y后面
{
le[ri[x]] = le[x];//自己画个链表应该就能明白了;\
le[x]为x节点的前驱,ri[x]为x节点的后继
ri[le[x]] = ri[x];
le[x] = y;
ri[x] = ri[y];
le[ri[y]] = x;
ri[y] = x;
}
void print()//输出
{
int mid=ri[0];
printf("%d",ri[0]);
while (ri[mid] < m+1)
{
printf(" %d", ri[mid]);
mid=ri[mid];
}
printf("\n");
}
int main()
{
int t;
scanf ("%d", &t);
while (t--)
{
int n;
scanf ("%d%d", &m, &n);
for (int i =1; i <=m; i++)//记录每个点的前驱与后继
{
le[i] = i-1;
ri[i] = i+1;
}
ri[0] = 1;//0是头结点
le[m + 1] = m;//m-1是空,即使用链表时的NULL
for (int i = 0; i <n; i++)
{
int d;
int x, y;
scanf ("%d", &d);
switch(d)
{
case 1:
scanf ("%d",&x);
swap(x,0);//将x节点插入到头结点的后面,即将x放到第一个
break;
case 2:
scanf ("%d", &x);
le[ri[x]] = le[x];//没办法用swap函数,只能自己写了
ri[le[x]] = ri[x];
ri[x] = m + 1;
le[x] = le[m +1];
ri[le[m + 1]] = x;
le[m +1] = x;
break;
case 3:
scanf ("%d%d", &x, &y);//x放到y后面
swap(x,y);
break;
}
}
print();
}
return 0;
}