#include<iostream>
using namespace std;
const int MAX=100010;
int RIGHT[MAX];
int LEFT[MAX];
void link(int l,int r);
int main()
{
int n,m;
int kase=1;
while(cin>>n>>m)
{
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;
bool flag=false;
while(m--)
{
cin>>op;
if(op==4)
{
flag=!flag;
}
else
{
cin>>x>>y;
int lx=LEFT[x],rx=RIGHT[x];
int ly=LEFT[y],ry=RIGHT[y];
if(op!=3&&flag)
{
op=3-op;
}
if(op==1&&x==LEFT[y])
{
continue;
}
if(op==2&&x==RIGHT[y])
{
continue;
}
if(op==1)
{
link(lx,rx);
link(ly,x);
link(x,y);
}
if(op==2)
{
link(lx,rx);
link(y,x);
link(x,ry);
}
if(op==3)
{
if(x==LEFT[y])
{
link(lx,y);
link(y,x);
link(x,ry);
}
else if(x==RIGHT[y])
{
link(ly,x);
link(x,y);
link(y,rx);
}
else
{
link(lx,y);
link(y,rx);
link(ly,x);
link(x,ry);
}
}
}
}
int a=0;
long long ans=0;
for(int i=1;i<=n;i++)
{
a=RIGHT[a];
if(i%2==1)
{
ans=ans+a;
}
}
if(flag&&n%2==0)
{
ans=(long long)(n/2)*(n+1)-ans;
}
cout<<"Case "<<kase<<":"<<ans<<endl;
kase++;
}
}
void link(int l,int r)
{
RIGHT[l]=r;
LEFT[r]=l;
}
解析:
采用双向链表,用left[i]与right[i]分别存储标号为i的盒子左边和右边的盒子的标号(如果是0,则表示不存在),link函数使得两的个盒子互相连接。操作4比较特殊,为了避免一次性修改所有元素的指针,增加一个布尔变量flag来标志当前的编号是否被转置。true表示被转置,反之没被转置。当op为1,2且flag=true时,只需要把op变为3-op(互相等价的),操作3不受4的影响。输出要根据盒子总数的奇偶性和flag的真假来调整。