CSU 1329~一行盒子(模拟链表)

来源:互联网 发布:水杨酸洗面奶 知乎 编辑:程序博客网 时间:2024/05/21 17:02

一行盒子

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 4 
1 1 4 
2 3 5 
3 1 6 

6 3 
1 1 4 
2 3 5 
3 1 6 
100000 1 
4

Sample Output

Case 1: 12 
Case 2: 9 
Case 3: 2500050000

Source 
湖南省第九届大学生计算机程序设计竞赛

模拟链表,pre[]表示该点左边的点,next[]表示该点右边的点;

模拟操作,比如将x移到y左边,则(移动前x左边的点)他的右边应该变为(移动前x右边的点),其余以此类推

注意,一定要将周围的关系变动好了再转移,比如x要移到y右边,先将x的左右关系处理好,再转移,切记!!

对于反转,只需要标记反转了几次,反转了偶数次和不反转一样,反转奇数次,移到y左边变为移到右边,移到右边变为移到左边

反转为奇数时op=1  变为op=2,op=2,变为op=1,则直接用3-op

找开头和结尾和遍历也十分关键,因为经过一定次数的操作后,开头不一定是pre[0]或next[n](反转),所以要寻找开头pre[x]或next[x](反转)=0这里要把它成环;即next[n]=0,与左边的开头pre[0]就连了起来,形成环,在遍历的时候就可以从开头一直遍历到结尾;

还有移动的时候要考虑相邻的特殊情况

#include<stdio.h>#include<string.h>#define maxn 100000+5typedef long long LL;int pre[maxn],next[maxn],n,m;int main(){    int T=0;    while(~scanf("%d%d",&n,&m))    {        int tot=0;        for(int i=1;i<=n;++i)        {            pre[i]=i-1;            next[i]=i+1;        }        next[n]=0;        //        int op,x,y;        for(int i=1;i<=m;++i)        {            scanf("%d",&op);            if(op!=4)            scanf("%d%d",&x,&y);            else            {                ++tot;                continue;            }            if((tot&1)&&op<3)                op=3-op;            if(op==1)            {            if(pre[y]==x)            continue;            next[pre[x]]=next[x];            pre[next[x]]=pre[x];            next[pre[y]]=x;            pre[x]=pre[y];            next[x]=y;            pre[y]=x;            }            else if(op==2)            {                if(next[y]==x)                    continue;                next[pre[x]]=next[x];                pre[next[x]]=pre[x];                pre[next[y]]=x;                next[x]=next[y];                pre[x]=y;                next[y]=x;            }            else if(op==3)            {                if(next[x]==y)                {                    int temp1=pre[x],temp2=next[y];                    next[temp1]=y;                    pre[y]=temp1;                    pre[temp2]=x;                    next[x]=temp2;                    next[y]=x;                    pre[x]=y;                }                else if(next[y]==x)                {                    int temp1=pre[y],temp2=next[x];                    next[temp1]=x;                    pre[x]=temp1;                    pre[temp2]=y;                    next[y]=temp2;                    next[x]=y;                    pre[y]=x;                }                else                {                    int temp1=next[y],temp2=pre[y];                    next[pre[x]]=y;                    pre[next[x]]=y;                    next[pre[y]]=x;                    pre[next[y]]=x;                    next[y]=next[x];                    pre[y]=pre[x];                    next[x]=temp1;                    pre[x]=temp2;                }            }        }           int *st,*ed;            if(tot&1)            {                st=next;                ed=pre;            }            else            {                st=pre;                ed=next;            }            LL ans=0;            for(int i=1;i<=n;++i)            {                if(!st[i])//寻找开头                {                    for(int j=1; i ;i=ed[i],++j)//判断结尾,i=0也就是末尾的时候循环结束                        if(j&1)                        ans+=i;                    break;                }            }        printf("Case %d: %lld\n",++T,ans);    }    return 0;}



0 0
原创粉丝点击