ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

GMOJ 6943. 【2020.01.05冬令营模拟】社会实践(practice)

2021-01-10 20:36:17  阅读:215  来源: 互联网

标签:冬令营 05 2020.01 text 起始 mid int 花费 步数


GMOJ6943. 社会实践(practice)

\(Description\)

给定一个长度为 \(n\) 仅由 \(\text{{1, 2, 3}}\) 构成的序列 \(s\),\(s_i\) 表示若由盘子 \(i\) 构成询问,那么 \(i\) 会在柱子 \(s_i\) 上,盘 \(1 \text{ ~ } n\) 大小单调递增,且每根柱上的盘大小递增。及 \(m\) 个操作:

  • 修改操作:给定 \(x, \ v\),将 \(s_x\) 修改为 \(p\)。
  • 询问操作:给定 \(l, \ r\),表示询问由区间 \([l, r]\) 构成,求将所有盘子移到一根柱上的 最少移动步数

\(Data \ Constraint\)

\(1 \leq n, \ m \leq 3 \times 10^5\)。

\(Solution\)

考虑询问的逆向操作:一开始盘 \(l \text{ ~ } r\) 都在同一根柱上,求移回相应柱子的最少移动步数。

那么有一个明显的贪心:将一摞盘子放在盘 \(r\) 对应的柱上,从大到小一次复位。

考虑一次操作,若盘 \(i\) 不在相应的柱上,那么我们需花费 \(2^{i - l} - 1\) 步将盘 \(l \text{ ~ } i - 1\) 移到除当前柱和目标柱的另一根柱上,然后花费 \(1\) 步复位 \(i\),共花费 \(2^{i - l}\) 步。

经过这次操作,复位了 \(i \text{ ~ } r\),盘 \(l \text{ ~ } i - 1\) 整体没变并且被移到了另一根柱子上,这是一个子问题。

那么若不固定起始柱的话,对于还原一个区间 \([l, r]\),可以由三个量表示:起始柱,花费步数,终止柱(即复位 \(l\) 后若还有盘的话会放在哪一根柱子) ,并且如果我们知道了 起始柱花费步数终止柱 就是唯一确定的。

所以我们便可以用线段树维护,对于每个区间存下起始柱及其对应的花费步数和终止柱,合并也很简单,直接枚举右区间的起始柱,那么其终止柱就是复位到左区间时的起始柱,总花费就为 左区间花费 + 右区间花费 \(\times 2^{mid - l + 1}\)

\(Code\)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define N 300000
#define mo 998244353

#define fo(i, x, y) for(int i = x; i <= y; i ++)

void read(int &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}

int a[N + 1], mi[N + 1];

int n, m;

namespace Tree { 
    #define lson (t << 1)
    #define rson (t << 1 | 1)
    int ls[N << 2][3], cs[N << 2][3];
    void Pushu(int t, int l, int r, int mid) {
        fo(i, 0, 2) {
            ls[t][i] = ls[lson][ls[rson][i]];
            cs[t][i] = (cs[lson][ls[rson][i]] + 1ll * cs[rson][i] * mi[mid - l + 1] % mo) % mo;
        }
    }
    void Build(int t, int l, int r) {
        if (l == r) {
            fo(i, 0, 2)
                cs[t][i] = a[l] == i ? (ls[t][i] = i, 0) : (ls[t][i] = (3 ^ a[l] ^ i), 1);
            return;
        }
        int mid = l + r >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Pushu(t, l, r, mid);
    }
    void Chang(int t, int l, int r, int k) {
        if (l == r) {
            fo(i, 0, 2)
                cs[t][i] = a[l] == i ? (ls[t][i] = i, 0) : (ls[t][i] = (3 ^ a[l] ^ i), 1);
            return;
        }
        int mid = l + r >> 1;
        k <= mid ? Chang(lson, l, mid, k) : Chang(rson, mid + 1, r, k);
        Pushu(t, l, r, mid);
    }
    int now = 0, ans = 0;
    void Calc(int t, int l, int r, int x, int y) {
        if (x <= l && r <= y) {
            (ans += 1ll * cs[t][now] * mi[l - x] % mo) %= mo, now = ls[t][now];
            return;
        }
        int mid = l + r >> 1;
        if (y > mid) Calc(rson, mid + 1, r, x, y);
        if (x <= mid) Calc(lson, l, mid, x, y);
    }
    #undef lson
    #undef rson
}

using namespace Tree;

int main() {
    freopen("practice.in", "r", stdin);
    freopen("practice.out", "w", stdout);

    read(n), read(m);
    fo(i, 1, n) read(a[i]), -- a[i];

    mi[0] = 1;
    fo(i, 1, n) mi[i] = 1ll * mi[i - 1] * 2 % mo;
    Build(1, 1, n);

    int opt, x, y;
    fo(Case, 1, m) {
        read(opt), read(x), read(y);
        if (opt == 1) {
            if (a[x] == -- y) continue;
            a[x] = y;
            Chang(1, 1, n, x);
        } else {
            now = a[y], ans = 0;
            Calc(1, 1, n, x, y);
            printf("%d\n", ans);
        }
    }

    return 0;
}

标签:冬令营,05,2020.01,text,起始,mid,int,花费,步数
来源: https://www.cnblogs.com/zhouzj2004/p/14259405.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有