CSU 1329 一行盒子

湖南第九届省赛~

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=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

思路:用数组模拟链表操作~,next[]表示某个节点的后继,pre[]表示某个节点的前驱;

(1)当要反转整条链的时候,其实实际上不需要反转,只需要逻辑上转换一下;
#include <stdio.h> 
const int N=1e6+100; 
using namespace std; 
int n,m; 
int pre[N],next[N]; 
  
void init() 
{ 
 for(int i=1;i<=n;i++) 
 { 
   pre[i]=i-1; 
   next[i]=i+1; 
 } 
 next[n]=0; 
} 
void do_pre(int x) 
{ 
  int k1=pre[x]; 
  int k2=next[x]; 
  pre[k2]=k1; 
  next[k1]=k2; 
} 
void left(int k,int x,int y) 
{ 
  next[k]=x; 
  next[x]=y; 
  pre[y]=x; 
  pre[x]=k ; 
} 
void right(int k,int x,int y) 
{ 
  next[y]=x; 
  next[x]=k; 
  pre[k]=x; 
  pre[x]=y; 
} 
  
void swap(int x,int y)  //这个地方容易出错,如果把判断条件写成  x+1==y   ||  y+1==x,那就回TLE,原因自己想
{ 
  int k1=pre[x],k2=next[x],k3=pre[y],k4=next[y]; 
  if(k2==y) 
  { 
    next[k1]=y; next[y]=x; next[x]=k4; 
    pre[k4]=x;  pre[x]=y;  pre[y]=k1; 
  } 
  else if(k4==x) 
  { 
    next[k3]=x; next[x]=y;  next[y]=k2; 
    pre[k2]=y;  pre[y]=x;   pre[x]=k3; 
  } 
  else
  { 
    next[k1]=y; next[y]=k2; 
    pre[k2]=y;  pre[y]=k1; 
  
    next[k3]=x; next[x]=k4; 
    pre[k4]=x;  pre[x]=k3; 
  } 
} 
  
  
int main() 
{ 
  int test=1; 
  while(scanf("%d%d",&n,&m)!=EOF) 
  { 
   init(); 
   int t=0; 
   while(m--) 
   { 
  
    int op,a,b; 
    scanf("%d",&op); 
    if(op==4)t++; 
    else
    { 
      if((op<3)&&(t&1))op=3-op; 
      if(op==1) 
      { 
       scanf("%d%d",&a,&b); 
       do_pre(a);//预先处理一下 
       int k=pre[b]; 
       left(k,a,b); 
      } 
      else if(op==2) 
      { 
       scanf("%d%d",&a,&b); 
       do_pre(a); 
       int k=next[b]; 
       right(k,a,b); 
      } 
      else if(op==3) 
      { 
       scanf("%d%d",&a,&b); 
       swap(a,b); 
      } 
    } 
  
   } 
  
  
   int *fs=NULL,*ls=NULL; 
   if(t&1) 
   { 
     fs=next; 
     ls=pre; 
   } 
   else
   { 
     fs=pre; 
     ls=next; 
   } 
   long long ans=0; 
   for(int i=1;i<=n;i++) 
     if(fs[i]==0) 
     { 
         for(int j=1;i;j++,i=ls[i])if(j&1)ans+=i; 
         break; 
     } 
   printf("Case %d: %lld\n",test++,ans); 
  
  } 
  return 0; 
} 
  
/************************************************************** 
    Problem: 1329 
    User: liusuangeng 
    Language: C++ 
    Result: Accepted 
    Time:272 ms 
    Memory:8780 kb 
****************************************************************/ 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值