题目:https://odzkskevi.qnssl.com/174f024bd53291a2e247beeba3bb72fe?v=1531723110
思路:这题是按照紫书上的思路来做的。就一边贴代码一边讲解吧。其实按照紫书上代码来的话,在草稿纸上画一遍就明白了。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int Right[100005],Left[100005];//Right[i]代表i左边的结点的编号,left[i]代表i右边的结点的编号
void link(int L,int R)//连接两个结点,注意:这个函数只是把两个结点中间相连了,也就是两个点中间不再有别的点了,但是他们另一边的值还要做处理
{
Right[L]=R;
Left[R]=L;
}
int main()
{
int n,num;
int tot=0;
while(scanf("%d%d",&n,&num)!=EOF){
tot++;
memset(Right,0,sizeof(Right));
memset(Left,0,sizeof(Left));
for(int i=1;i<=n;i++)
{
Left[i]=i-1;
Right[i]=(i+1)%(n+1);
}
Left[0]=n,Right[0]=1;
int inv=0;int op;int x,y;
while(num--)
{
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;
int lx=Left[x],rx=Right[x],ly=Left[y],ry=Right[y];
if(op==1){//拿op=1来举例,先让lx和rx相连,于是x被完美地挤出去了,但是x的两边的值依然是lx和rx,所以我们要改变x两边的值,先让x的左边等于ly,ly的右边等于x,即ly和x相连,再改变x的右边,让x和y相连。
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);}
else{
link(lx,y);
link(y,rx);
link(ly,x);
link(x,ry);
}
}
}
}
long long int sum=0;
int b=0;
for(int i=1;i<=n;i++)
{
b=Right[b];
if(i%2==1)sum=sum+b;
}
if(inv&&n%2==0)sum=(long long int)(1+n)*n/2-sum;//当n是偶数且inv是1时(也就是链表反向的时候,我们求的和是偶数的和而不是奇数的和,所以要用总数减一下)
printf("Case %d: %lld\n",tot,sum);
}
return 0;
}