CSUOJ 1982 小M的移动硬盘
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
Hint
这道题之前见过好几次,没有一次写出来过,前几天认真研究了一下,终于写出来了。
思路:对每个位置,用l 和r两个数组记录该位置前面和后面的数的编号,每次变动的时候更新一下就好了。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define MAXN 300010 typedef long long ll; int m, n; int l[MAXN], r[MAXN]; void init() { r[0] = 1; l[n + 1] = n; for (int i = 1; i <= n; i++) { l[i] = i - 1; r[i] = i + 1; } } void con(int x, int y) { r[x] = y; l[y] = x; } int main() { int T,x,u,v; while (cin >> T) { while (T--) { cin >> n >> m; init(); for (int i = 0; i < m; i++) { cin >> x; if (x == 1) { cin >> u; if (r[0] == u) continue; int l_u = l[u],r_u=r[u],r0=r[0]; con(l_u, r_u); con(u, r0); con(0, u); } else if (x == 2) { cin >> u; if (l[n+1] == u) continue; int l_u = l[u], r_u = r[u], l_n = l[n+1]; con(l_u, r_u); con(l_n, u); con(u, n+1); } else { cin >> u >> v; if (r[v] == u) continue; int l_u = l[u], r_u = r[u], r_v = r[v]; con(l_u, r_u); con(u, r_v); con(v, u); } } int temp = r[0]; cout << temp; while (r[temp] != (n + 1)) { cout << " " << r[temp]; temp = r[temp]; } cout << endl; } } return 0; } /********************************************************************** Problem: 1982 User: leo6033 Language: C++ Result: AC Time:984 ms Memory:4368 kb **********************************************************************/这题还能用链表来写,可以自己思考思考