Uva12657 Boxes in a Line

题目链接:传送门

分析:每次操作都会花费大量时间,显然我们只需要关注每个元素的左边是啥,右边是啥就够了,那么用双向链表,l[i]表示i左边的数,r[i]表示i右边的数,每次操作模拟一下数组的变化就好了.

      不过这样有一个问题:第4个操作似乎无法很高效地进行,如果真的按照它说的那样模拟翻转,恐怕复杂度和暴力也要差不多了,那么我们怎么处理呢?

      观察发现题目只让我们输出奇数位置的编号和,也就是说,如果题目给定的序列长度就是奇数的,那么无论用多少次4操作都没有影响,否则4的次数是奇数,则用总和减去当前奇数位置的和就是答案。这就相当于线段树中的lazy标记的做法,现在要考虑这个标记对其它操作的影响,显然对3操作是没有任何影响的,而对1,2操作无非就是把1变成了2,把2变成了1,这样就很快地就能解决问题了。

如果数据结构上的某一个操作很耗时,有时可以用加标记的方式处理,而不需要真的执行那个操作。但同时,该数据结构的所有其他操作都要考虑这个标记!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 100010;

int n, m, kase, l[maxn], r[maxn],flag;
long long ans;

int main()
{
    while (scanf("%d%d", &n, &m) == 2)
    {
        for (int i = 1; i <= n; i++)
        {
            l[i] = i - 1;
            r[i] = (i + 1) % (n + 1);
        }
        l[0] = n; 
        r[0] = 1;
        flag = 0;
        for (int i = 1; i <= m; i++)
        {
            int op,x,y;
            scanf("%d", &op);
            if (op == 4)
                flag = (flag + 1) % 2;
            else
            {
                scanf("%d%d", &x, &y);
                if (op != 3 && flag)
                    op = 3 - op;
                if (op == 1 && l[y] == x)
                    continue;
                if (op == 2 && r[y] == x)
                    continue;
                
                if (op == 1)
                {
                    l[r[x]] = l[x];
                    r[l[x]] = r[x];
                    r[l[y]] = x;
                    r[x] = y;
                    l[x] = l[y];
                    l[y] = x;
                }
                else
                    if (op == 2)
                    {
                    l[r[x]] = l[x];
                    r[l[x]] = r[x];
                    l[x] = y;
                    r[x] = r[y];
                    l[r[y]] = x;
                    r[y] = x;
                    }
                    else
                        if (op == 3)
                        {
                    if (r[x] == y)
                    {
                        r[l[x]] = y;
                        l[y] = l[x];
                        r[y] = x;
                        l[x] = y;
                        r[x] = r[y];
                        l[r[y]] = x;
                    }
                    else
                    {
                        r[l[y]] = x;
                        l[r[y]] = x;
                        r[l[x]] = y;
                        l[r[x]] = y;
                        swap(l[x], l[y]);
                        swap(r[x], r[y]);
                    }
                        }
            }
            int cur = 0;
            ans = 0;
            for (int i = 1; i <= n; i++)
            {
                cur = r[cur];
                if (i % 2 == 1)
                    ans += cur;
            }
            if (flag && n % 2 == 0)
                ans = (long long)n * (n + 1) / 2 - ans;
        }
        printf("Case %d: %lld
", ++kase, ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7571319.html