UVA 12657 Boxes in a Line(双向链表+小技巧)
题意:对于一行按照顺序排列盒子数字与位置都为 1,2,3,4....n
执行四种操作
c = 1 x 放到 y 的左边
c =2 x 放到 y 的右边
c =3 交换 x, y
c =4 颠倒链
最后求出奇数位置的数的总和
题解:直接维护无论如何每次每次都需要维护一段区间的位置,因此不去看位置、只需要知道每个盒子左边是哪个盒子右边是哪个盒子
这样就直接使用双向链表维护,接着颠倒时注意只是标记就好
最后注意几个细节:
首先颠倒后1与2的交换需要互换;
维护链表时可以提取出一个函数,每次都只需要多次使用这个函数;
c等于1,2,3时x与y的位置相邻时会出现很大的问题
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<iomanip> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<28; const ll INF=1LL<<60; const double Pi=acos(-1.0); const int Mod=1e9+7; const int Max=100010; struct node { int left,right; } ball[Max];//**表示i这个数字左右两边的数字** void initPosition(int n)//双向链表初始化 { for(int i=1; i<=n; ++i) { ball[i].left=i-1; ball[i].right=(i+1)%(n+1); } } void link(int l,int r)//左右相互连接 { ball[l].right=r; ball[r].left=l; } inline void Solve(int type,int &mark) { if(type==4) { mark=(mark^1); return; } if(type!=3&&!mark) type=3-type;//注意反转后只需交换type的1与2就好 int x,y; scanf("%d %d",&x,&y); int Lx=ball[x].left; int Rx=ball[x].right; int Ly=ball[y].left; int Ry=ball[y].right; if(type==1&&Rx==y||type==2&&Lx==y) return; if(type==1)//通过下标找到x、y,将x放在y的左边 { link(Lx,Rx);//**找到6个交换的规律** link(Ly,x); link(x,y); } else if(type==2) { link(Lx,Rx); link(x,Ry); link(y,x); } else if(type==3) { if(Rx==y)//注意 { link(Lx,y); link(y,x); link(x,Ry); } else if(Lx==y){ link(y,Rx); link(Ly,x); link(x,y); } else { link(y,Rx); link(Ly,x); link(Lx,y); link(x,Ry); } } } ll Print(int n,int mark) { ll res=0LL; int start=0; for(int i=1; i<=n; ++i) { if(ball[i].left==0) { start=i; break; } } int now=start; int coun=0; while(now) { res+=now; now=ball[now].right; if(now) now=ball[now].right; } if(!(n&1)&&!mark) res=(ll)n*(n+1)/2-res; return res; } int main() { int n,m; int coun=0; while(~scanf("%d %d",&n,&m)) { initPosition(n); int mark=1;//标记是否反转 while(m--) { int type; scanf("%d",&type); Solve(type,mark); } printf("Case %d: %lld\n",++coun,Print(n,mark)); } return 0; }