/*
小白书上给出了代码,但是对于代码的解释,不是特别详细,这个博客就比较详细,基本写出了几种分类的依据和考虑,以及如何对于哪些情况,要特别拿出来特判
博客:
http://blog.csdn.net/acmore_xiong/article/details/47753589
注意:
1. 虽然小白书上定义的数组名是 left 和 right ,但是不太建议用这两个,因为小白书给出的是C的代码,但如果用到C++ left和right会和 <iostream>头文件中,用于控制IO输入输出格式的 left 和 out 同名,引起二义性,可以将数组名改为大写来解决这个问题
或者,就不用<iostream>头文件了,这题用它主要是想运用自带的swap函数,但是如果只包含 <algorithm>头文件,也能达到同样的效果
收获:(具体见小白书P145-148)
1. 双向链表等复杂的链式结构中,往往会编写一些辅助函数来设置链接关系,例如该题的 link函数
2. 如果数据结构上某一个操作耗时,可以加标记来处理,而不用真的执行那个操作。但同时,该数据结构所有其他操作都要考虑这个标记
3. 复杂链式结构往往容易写错,编码结束后,为了确保程序准确性,测试和调试往往要交替进行
4. 对拍--对于某份可能出错的程序,应该再编写一份速度可能不优,但正确性能得到绝对保证的另一份代码。利用数据生成器(随机数生成函数等),来生成随机数据,执行两个程序,比较它们的结果(简易版本越简单越好,不重在速度,重在正确性)
5.
数据复杂性会增大调试难度。找到使程序出错的数据后,应尝试简化数据,或者用更小的参数调用数据生成器,找到更简单的错误数据
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int left[maxn], right[maxn], n, m;
void link(int L, int R)
{
right[L] = R; left[R] = L;
}
int main()
{
int kase = 0;
while (scanf("%d%d", &n, &m) == 2)
{
for (int i = 1; i <= n; i++)
{
left[i] = i - 1;
right[i] = (i + 1) % (n + 1);
}
left[0] = n;
right[0] = 1;//实现双向链表
int op, X, Y, inv = 0;
while (m--)
{
scanf("%d", &op);
if (op == 4) inv = !inv;
else
{
scanf("%d%d", &X, &Y);
if (op == 3 && right[Y] == X) swap(X, Y);
if (op != 3 && inv) op = 3 - op;
if (op == 1 && left[Y] == X) continue;
if (op == 2 && right[Y] == X) continue;
//注意:后两条语句一定要放前两条语句的后面
//因为我们对 4操作是加了标记的,所以,所有其他操作,都要考虑那个标记的影响,之前满足后两个if还不算,一定要在考虑了4的标记的可能影响以后,仍然满足if,才是真正能continue的情况
int LX = left[X], RX = right[X], LY = left[Y], RY = right[Y];
if (op == 1)
{
link(LX, RX); link(LY, X); link(X, Y);
}
else if (op == 2)
{
link(LX, RX); link(Y, X); link(X, RY);
}
else if (op == 3)
{
if (right[X] == Y)
{
link(LX, Y); link(Y, X); link(X, RY);
//在这种情况下,可画图发现,X == LY, Y == RX,所以这里的X和Y,可以分别用LY和RX替换掉
}
else
{
link(LX, Y); link(Y, RX); link(LY, X); link(X, RY);
}
}
}
}
int b = 0;
long long ans = 0;
for (int i = 1; i <= n; i++)
{
b = right[b];
if (i % 2) ans += b;
}
if (inv && n % 2 == 0) ans = (long long)n * (n + 1) / 2 - ans;
printf("Case %d: %lld
", ++kase, ans);
}
}