想都不用想,用list直接模拟肯定超时,只能自己手写
用两个数组le和ri,写一个双向链表,le[x]表示盒子x左边的盒子编号,ri[x]表示盒子x右边的盒子编号,实际上就是一个双向链表 。只不过我们通过两个数组模拟之后可以O(1)的拿到某一个特定元素的左右指针而已
另外一个变量记录这个链表的开头,输出结果的时候遍历一遍就好
至于reverse操作,用一个bool变量标记一下,在有标记的情况下,放左边和放右边的操作需要反过来,证明的话,证明做完反操作之后有标记的这条链就是老老实实按操作做完的链表的逆置即可,想一想就知道了。
swap的时候注意一下x和y相邻的情况,假如x和y不相邻,则需要最多要改8个指针,否则最多6个
有点难写。。。WA了好几发,陷入 死循环了好几发。。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
using ll=long long;
const int maxm=100010;
int n,m,x,be,y,oper,le[maxm],ri[maxm],kcase;
bool re;
void put_left(),put_right(),swp();
ll getans();
int main(){
ios_base::sync_with_stdio(false);
while(cin>>n>>m){
be=1;
for(int i=1;i<=n;++i)
le[i]=i-1,ri[i]=i+1;
ri[n]=0;
while(m--){
cin>>oper;
if(oper==4)
re=!re;
else{
cin>>x>>y;
if(oper==1&&!re||oper==2&&re)
put_left();
else if(oper==1&&re||oper==2&&!re)
put_right();
else if(oper==3)
swp();
}
}
cout<<"Case "<<++kcase<<": "<<getans()<<endl;
re=false;
}
return 0;
}
void put_left(){
if(be==x)
be=ri[x];
else if(be==y)
be=x;
if(le[x])
ri[le[x]]=ri[x];
if(ri[x])
le[ri[x]]=le[x];
if(le[y])
ri[le[y]]=x;
le[x]=le[y];
le[y]=x;
ri[x]=y;
}
void put_right(){
if(be==x)
be=ri[x];
if(le[x])
ri[le[x]]=ri[x];
if(ri[x])
le[ri[x]]=le[x];
if(ri[y])
le[ri[y]]=x;
ri[x]=ri[y];
ri[y]=x;
le[x]=y;
}
void swp(){
if(be==x)
be=y;
else if(be==y)
be=x;
if(ri[x]==y)
put_right();
else if(le[x]==y)
put_left();
else{
int tmp1=le[y],tmp2=ri[y];
if(le[x])
ri[le[x]]=y;
if(ri[x])
le[ri[x]]=y;
le[y]=le[x];
ri[y]=ri[x];
if(tmp1)
ri[tmp1]=x;
if(tmp2)
le[tmp2]=x;
le[x]=tmp1;
ri[x]=tmp2;
}
}
ll getans(){
ll ans=0;
if(!(n&1)&&re)
be=ri[be];
for(bool flag=true;be;be=ri[be],flag=!flag)
if(flag)
ans+=be;
return ans;
}