csu 1329 一行盒子(链表操作)
1329: 一行盒子
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 693 Solved: 134
[Submit][Status][Web
Board]
Description
你有一行盒子,从左到右依次编号为1, 2, 3,…, n。你可以执行四种指令:
1 X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
2 X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
3 X Y表示交换盒子X和Y的位置。
4 表示反转整条链。
指令保证合法,即X不等于Y。例如,当n=6时在初始状态下执行1 1 4后,盒子序列为2 3 1 4 5 6。接下来执行2 3 5,盒子序列变成2 1 4 5 3 6。再执行3 1 6,得到2 6 4 5 3 1。最终执行4,得到1 3 5 4 6 2。
Input
输入包含不超过10组数据,每组数据第一行为盒子个数n和指令条数m(1<=n,m<=100,000),以下m行每行包含一条指令。
Output
每组数据输出一行,即所有奇数位置的盒子编号之和。位置从左到右编号为1~n。
Sample Input
6 41 1 42 3 53 1 646 31 1 42 3 53 1 6100000 14
Sample Output
Case 1: 12Case 2: 9Case 3: 2500050000
第一次做这类型的题,真的有蛮坑的,特别是SAWP操作,情况漏考虑就是死循环,唉,做个模板用吧。。。这题两点要注意,一是我们只要在逻辑上面进行翻转
即可,如果是奇数次,那么只要将1操作看成2操作,2操作看成1操作即可。然后最后输出的时候也只要奇数次翻转就从尾部开始算,偶数次就从头部开始算。
swap(x,y)一定要考虑 next[x] = y和next[y] = x两种情况。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn = 200005; int n,m; int chi[maxn],pre[maxn]; void init() { pre[1] = 0; for(int i = 2; i <= n; i++) pre[i] = i - 1; for(int i = n-1; i >= 1; i--) chi[i] = i + 1; chi[n] = 0; } void left(int x,int y){ ///将x 移到y的左边 if(pre[y]==x) return; int p = pre[x]; //x的父亲节点 pre[chi[x]] = p,chi[p] = chi[x]; p = pre[y],chi[p] = x; pre[x] = p,chi[x] = y,pre[y] = x; } void right(int x,int y){ ///将x移向y的右边 if(chi[y]==x) return; int p = pre[x]; //x的父亲节点 pre[chi[x]] = p,chi[p] = chi[x]; pre[x] = y,chi[x] = chi[y]; pre[chi[y]] = x,chi[y] = x; } void Swap(int x,int y){ ///链表的交换操作 int p1 = pre[x],p2 = pre[y]; int c1 = chi[x],c2 = chi[y]; if(chi[x]==y){ chi[p1]=y,chi[y]=x,chi[x]=c2; pre[c2]=x,pre[x]=y,pre[y]=p1; }else if(chi[y]==x){ chi[p2]=x,chi[x]=y,chi[y]=c1; pre[c1]=y,pre[y]=x,pre[x]=p2; }else{ chi[p1] = y,pre[y] = p1; chi[y] = c1,pre[c1] = y; chi[p2] = x,chi[x] = c2; pre[c2] = x,pre[x] = p2; } } int main() { //freopen("b.in","r",stdin); //freopen("b.txt","w",stdout); int op,x,y; int cnt = 0,cas=1; while(scanf("%d %d",&n,&m)!=EOF) { init(); cnt = 0; while(m--) { scanf("%d",&op); if(op==4) cnt++; else { if(op<3&&cnt%2==1) op = 3-op; if(op == 1) { scanf("%d %d",&x,&y); left(x,y); } else if(op == 2) { scanf("%d %d",&x,&y); right(x,y); } else if(op == 3) { scanf("%d %d",&x,&y); Swap(x,y); } } } long long ans = 0; if(cnt % 2 == 1) //翻转了 { int head; for(int i = 1; i <= n; i++) if(chi[i] ==0) { head = i; break; } int f = 1; while(pre[head] != 0) { if(f%2==1) ans+=head; head = pre[head]; f++; } if(f%2==1) ans+=head; } else { int head; for(int i = 1; i <= n; i++) if(pre[i] == 0) { head = i; break; } int f = 1; while(chi[head] !=0) { if(f%2==1) ans+=head; head = chi[head]; f++; } if(f%2==1) ans+=head; } printf("Case %d: %I64d\n",cas++,ans); } return 0; }