12657 - Boxes in a Line

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。可以执行以下4种指令:

  • 1 X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
  • 2 X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
  • 3 X Y表示交换盒子X和Y的位置。
  • 4 表示反转整条链。

指令保证合法,即X不等于Y。例如,当n=6时在初始状态下执行114后,盒子序列为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。

输入包含不超过10组数据,每组数据第一行为盒子个数n和指令条数m(1≤n,m≤100000),以下m行每行包含一条指令。每组数据输出一行,即所有奇数位置的盒子编号之和。位置从左到右编号为1~n。

样例输入:

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

样例输出:

Case 1: 12

Case 2: 9

Case 3: 2500050000

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxNum = 100005;
// 盒子
int box[maxNum];
// 左链表
int left[maxNum];
// 右链表
int right[maxNum];

// 连接L,R结点
void link(int L, int R) {
    left[R] = L;
    right[L] = R;
}

int main() {
    // n个盒子
    // m条操作
    int n, m, kase = 0;
    while(scanf("%d%d", &n, &m) != EOF) {
        // 初始化
        for(int i = 1; i <= n; i++) {
            // 盒子的值
            box[i] = i;
            // 盒子的左链表指向上一个元素
            left[i] = i - 1;
            // 盒子的右链表指向下一个元素
            right[i] = i + 1;
        }
        // 通过这个操作,使链表变成循环双链表
        right[0] = 1;
        left[0] = n;
        // 标记链表是否反转,默认为不反转
        bool isRev = false;
        // 操作
        int op;
        while(m--) {
            scanf("%d", &op);
            // 反转操作
            if(4 == op) {
                isRev = !isRev;
            } else {
                int X;
                int Y;
                scanf("%d%d", &X, &Y);
                // 使交换操作中的邻接情况,由
                // XY,YX两种变成XY一种
                if(3 == op && right[Y] == X) {
                    swap(X, Y);
                }
                // 反转之后,1,2操作交换
                if(3 != op && isRev) {
                    op = 3 - op;
                }
                // X已经在Y的左边了
                if(1 == op && left[Y] == X) {
                    continue;
                }
                // X已经在Y的右边了
                if(2 == op && right[Y] == X) {
                    continue;
                }

                // X的左边
                int XL = left[X];
                // X的右边
                int XR = right[X];
                // Y的左边
                int YL = left[Y];
                // Y的右边
                int YR = right[Y];

                // 将X放在Y的左边
                if(1 == op) {
                    // 连接X左边结点和右边结点
                    link(XL, XR);
                    // 连接Y的左边结点和X结点
                    link(YL, X);
                    // 连接X结点和Y结点
                    link(X, Y);
                } else if(2 == op) {
                    // 将X放在Y的右边
                    // 连接X左边结点和右边结点
                    link(XL, XR);
                    // 连接Y结点和X结点
                    link(Y, X);
                    // 连接X结点和Y的右边结点
                    link(X, YR);
                } else if(3 == op) {
                    // 交换X和Y结点
                    // XY相邻
                    if(right[X] == Y) {
                        // 连接X左边结点和Y结点
                        link(XL, Y);
                        // 连接Y结点和X结点
                        link(Y, X);
                        // 连接X结点和Y右边结点
                        link(X, YR);
                    } else {
                        // 连接X左边结点和Y结点
                        link(XL, Y);
                        // 连接Y结点和X右边结点
                        link(Y, XR);
                        // 连接Y左边结点和X结点
                        link(YL, X);
                        // 连接X结点和Y右边结点
                        link(X, YR);
                    }
                }
            }
        }
        int node = 0;
        long long ans = 0;
        for(int i = 1; i <= n; i++) {
            // 获取右结点
            node = right[node];
            // 因为结点和值一样,所以直接相加
            if(i % 2 == 1) {
                ans += node;
            }
        }
        // n为偶数且链表反转
        // PS:如果n为奇数,反转与不反转是一样的
        if(!(n % 2) && isRev) {
            // 因为是从1-n,所以反转取差就行了
            ans = (long long)n * (n + 1) / 2 - ans;
        }
        printf("Case %d: %lld\n", ++kase, ans);
    }
    return 0;
}
时间: 2024-10-12 14:12:30

12657 - Boxes in a Line的相关文章

uva 12657 - Boxes in a Line(AC和TLE的区别,为什么说STL慢..)

用STL中的list写的,TLE #include<cstdio> #include<iostream> #include<cstring> #include<list> #include<algorithm> using namespace std; list<int> l; list<int>::iterator it1,it2,it3,it4,it5,it; void work(int a,int a1=1,int

UVa 12657 Boxes in a Line(双向链表的应用)

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 th

UVa 12657 Boxes in a Line(应用双链表)

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 th

Uva 12657 Boxes in a Line 双向链表

操作4比较特殊,为了避免一次性修改所有元素的指针,由于题目只要求输出奇数盒子的编号,所以我们可以灵活的根据是否进行过操作4对操作1 操作2 进行改动 操作3不受操作4影响 上代码.... #include<cstdio> #include<algorithm> const int maxn=100000+5; int right[maxn],left[maxn]; void link (int L,int R){ right[L]=R;left[R]=L; } //在双向链表这样复

UVA 12657 Boxes in a Line

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4395 题目意思是说,给出一个数n,表示存在一个整数序列1--n,然后进行四种操作: 操作一:输入x,y,表示将x移到y的左边(若x本来就在y的左边则忽略): 操作二:输入x,y,表示将x移到y的右边(若x本来就在y的右边则忽略): 操作三:输入x,y,表示交换x和y. 操作四:将

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的交换需要互换: 维护链表时可以提取出一个函数,每

UVa 12657 Boxes in a Line(数组模拟双链表)

题目链接 1 /* 2 问题 3 将一排盒子经过一系列的操作后,计算并输出奇数位置上的盒子标号之和 4 5 解题思路 6 由于数据范围很大,直接数组模拟会超时,所以采用数组模拟的链表,left[i]和right[i]分别表示i号盒子的左边是谁和右边 7 是谁.特别提醒,4这个操作可以采用其他的办法去标记,而不必真的去模拟交换,否则会超时. 8 */ 9 10 #include<cstdio> 11 #include<algorithm> 12 13 using namespace

Uva12657 (Boxes in a Line)移动盒子

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 4kinds 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

O - Boxes in a Line

O - Boxes in a Line Time Limit:1000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description 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 t