你有一行盒子,从左到右依次编号为1, 2, 3,…, n。你可以执行四种指令:
1 X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
2 X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
3 X Y表示交换盒子X和Y的位置。
4 表示反转整条链。
指令保证合法,即X不等于Y。例如,当n=6时在初始状态下执行1 1 4后,盒子序列为2 3 1 4 5 6。接下来执行2 3 5,盒子序列变成2 1 4 5 3 6。再执行3 1 6,得到2 6 4 5 3 1。最终执行4,得到1 3 5 4 6 2。
输入包含不超过10组数据,每组数据第一行为盒子个数n和指令条数m(1<=n,m<=100,000),以下m行每行包含一条指令。
每组数据输出一行,即所有奇数位置的盒子编号之和。位置从左到右编号为1~n。
1 #include<iostream>
2 #include<algorithm>
3 #include<cstdio>
4 #include<cstring>
5 #include<queue>
6 #include<string>
7 #include<cmath>
8 using namespace std;
9 int *tmp1,*tmp2;
10 const int N = 1e5+10;
11 int LEFT[N],RIGHT[N];
12 void swap(int a,int b)
13 {
14 RIGHT[a] = b;
15 LEFT[b] = a;
16 }
17 int main()
18 {
19 int cas = 1;
20 int T,cnt,nest,flag,m,n,x,y;
21 while(~scanf("%d %d",&m,&n))
22 {
23 for(int i=1;i<=m;i++)//预处理
24 {
25 LEFT[i] = i-1;
26 RIGHT[i] = i+1;
27 }
28 RIGHT[m] = 0;
29 cnt = 0;
30 while(n--)
31 {
32 scanf("%d",&flag);
33 if(flag != 4) scanf("%d %d",&x,&y);
34 else cnt++;
35 if((cnt&1) && flag<3) flag = 3 - flag;
36 if(flag == 1 && LEFT[y]!=x)
37 {
38 swap(LEFT[x],RIGHT[x]);
39 swap(LEFT[y],x);
40 swap(x,y);
41 }
42 else if(flag == 2 && RIGHT[y]!=x)
43 {
44 swap(LEFT[x],RIGHT[x]);
45 swap(x,RIGHT[y]);
46 swap(y,x);
47 }
48 else if(flag == 3)
49 {
50 if(RIGHT[x] == y)//两者在挨着;
51 {
52 swap(LEFT[x],y);
53 swap(x,RIGHT[y]);
54 swap(y,x);
55 }
56 else if(LEFT[x] == y)
57 {
58 swap(LEFT[y],x);
59 swap(y,RIGHT[x]);
60 swap(x,y);
61 }
62 else
63 {
64 int t1 = LEFT[x],t2 = RIGHT[x],t3 = LEFT[y],t4 = RIGHT[y];
65 swap(t1,y);
66 swap(y,t2);
67 swap(t3,x);
68 swap(x,t4);
69
70 }
71 }
72 }
73 long long ans = 0;
74 if(cnt&1) //翻转一下
75 {
76 tmp2 = RIGHT;
77 tmp1 = LEFT;
78 }
79 else {
80 tmp2 = LEFT;
81 tmp1 = RIGHT;
82 }
83 for(int i=1;i<=m;i++)
84 {
85 if(tmp2[i] == 0)//寻找第一位
86 {
87 for(int k=1;i;i = tmp1[i],k++)
88 if(k&1) ans = ans+i;
89 printf("Case %d: %lld\n",cas++,ans);
90 break;
91 }
92 }
93 }
94 return 0;
95 }