UVA 12657 Boxes in a Line (双向链表)

You have n boxes in a line on the table numbered 1: : : n from left to right. Your task is to simulate 4
kinds of commands:
 1 X Y : move box X to the left to Y (ignore this if X is already the left of Y )
 2 X Y : move box X to the right to Y (ignore this if X is already the right of Y )
 3 X Y : swap box X and Y
 4: reverse the whole line.
Commands are guaranteed to be valid, i.e. X will be not equal to Y .
For example, if n = 6, after executing 1 1 4, the line becomes 2 3 1 4 5 6. Then after executing
2 3 5, the line becomes 2 1 4 5 3 6. Then after executing 3 1 6, the line becomes 2 6 4 5 3 1.
Then after executing 4, then line becomes 1 3 5 4 6 2
Input
There will be at most 10 test cases. Each test case begins with a line containing 2 integers n, m
(1  n; m  100;000). Each of the following m lines contain a command.
Output
For each test case, print the sum of numbers at odd-indexed positions. Positions are numbered 1 to n
from left to right.
Sample Input
6 4
1 1 4
2 3 5
3 1 6
4
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

题意:有一行盒子,从左到右一次编号为1,2,3,......n,可以执行四种命令:

1 X Y 把X移到Y左边(如果X已经在Y左边,则忽略)

2 X Y 把X移到Y右边(如果X已经在Y右边,则忽略)

3 X Y 交换X和Y的位置

4 翻转整条链

经过M次变换后,求整条链奇数位的和

 

分析:当初想通过分奇偶数情况,用前缀和还有整体操作来求解,但是后来发现数据操作的那个部分很不好写,所以用双向链表,这也是算法竞赛入门经典(第二版)的题目P144

通过left数组和right数组和link函数实现两个节点的连接,这里的Link函数很巧妙。

这题要注意因为4操作会对1操作和2操作进行改变,所以设置一个 inv ,最后输出的时候,也会有影响。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<stdlib.h>
#include<algorithm>
#define LL __int64
#define FIN freopen("in.txt","r",stdin)
using namespace std;
const int MAXN=100000+5;
int l[MAXN],r[MAXN];
int n,m;
void link(int L,int R)  //连接两个节点的link函数
{
    l[R]=L;
    r[L]=R;
}
int main()
{
    int Case=0;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            l[i]=i-1;
            r[i]=(i+1)%(n+1);
        }
        l[0]=n;
        r[0]=1;
        int inv=0,opt,X,Y;
        while(m--)
        {
            scanf("%d",&opt);
            if(opt==4) inv=!inv;
            else
            {
                scanf("%d %d",&X,&Y);
                if(opt==3 && r[Y]==X) swap(X,Y); //这里要注意一下,并不是交换了X,Y的位置,而是交换了X,Y的值,以便后面进行统一处理
                if(opt!=3 && inv) opt=3-opt;  //这里可以看成从后往前处理
                if(opt==1 && l[Y]==X) continue;
                if(opt==2 && r[Y]==X) continue;

                int LX=l[X],RX=r[X],LY=l[Y],RY=r[Y];
                if(opt==1)
                {
                    link(LX,RX);
                    link(LY,X);
                    link(X,Y);
                }
                if(opt==2)
                {
                    link(LX,RX);
                    link(Y,X);
                    link(X,RY);
                }
                if(opt==3)
                {
                    if(r[X]==Y)
                    {
                        link(LX,Y);
                        link(Y,X);
                        link(X,RY);
                    }
                    else
                    {
                        link(LX,Y);
                        link(Y,RX);
                        link(LY,X);
                        link(X,RY);
                    }
                }
            }
        }
        long long ans=0;  //注意最后结果可能会很大
        int b=0;
        for(int i=1;i<=n;i++)
        {
            b=r[b];
            if(i%2==1) ans+=b;
        }
        if(inv && n%2==0) ans=(long long)(n+1)*n/2-ans; //长度为偶数,翻转后所有数的总和减去偶数项的和
        printf("Case %d: %lld\n",++Case,ans);
    }
    return 0;
}
View Code

 

posted @ 2015-08-18 10:08  Cliff Chen  阅读(175)  评论(0编辑  收藏  举报