- 操作4比较特殊,为了避免一次性修改所有元素的指针,由于题目只要求输出奇数盒子的编号,所以我们可以灵活的根据是否进行过操作4对操作1 操作2 进行改动
- 操作3不受操作4影响
上代码。。。。
#include<cstdio> #include<algorithm> const int maxn=100000+5; int right[maxn],left[maxn]; void link (int L,int R){ right[L]=R;left[R]=L; } //在双向链表这样复杂的数据结构中,往往会编写一些辅助函数来设置链接关系 int main(){ int m,n,kase=0; while(scanf("%d%d",&n,&m)==2){ for(int i=1;i<=n;i++){ right[i]=(i+1)%(n+1); left[i]=i-1; } right[0]=1;left[0]=n; int op,x,y,flag=0; while(m--){ scanf("%d",&op); if (op==4) flag=!flag;//操作4是否执行奇数次 else{ scanf("%d%d",&x,&y); if(op==3&&right[y]==x) std::swap(x,y);//为了方便操作,避免重写第37行代码,当然你重写也可以 if(op!=3&&flag) op=3-op; if(op==1&&x==left[y]) continue;//如果x已经在y的左边则忽略此指令 if(op==2&&x==right[y]) continue;//如果x已经在y的右边则忽略此指令 int lx=left[x],rx=right[x],ly=left[y],ry=right[y]; if(op==1){ //插入到x的左边并删除原来x结点的位置 link(lx,rx);link(ly,x);link(x,y); } else if (op==2){ //插入到y的右边并删除原来x结点的位置 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);//y插入到x的位置 link(ly,x);link(x,ry);//x插入到y的位置 } } } } int b=0; long long ans=0; for (int i=1;i<=n;i++){ b=right[b]; if(i&1) ans+=b; } if(flag&&n%2==0) ans=(long long)n*(n+1)/2-ans; printf("Case %d: %lld ",++kase,ans); } return 0; } /* 样例输入: 6 4 1 1 4 2 3 5 3 1 6 4 6 3 1 1 4 2 3 5 3 1 6 100000 1 4 样例输出: case 1: 12 case 2: 9 case 3: 2500050000 */