NC20279 [SCOI2010]序列操作

这篇具有很好参考价值的文章主要介绍了NC20279 [SCOI2010]序列操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目链接

题目

题目描述

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

0 a b 把[a, b]区间内的所有数全变成0

1 a b 把[a, b]区间内的所有数全变成1

2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0

3 a b 询问[a, b]区间内总共有多少个1

4 a b 询问[a, b]区间内最多有多少个连续的1

对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入描述

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目
第二行包括n个数,表示序列的初始状态
接下来m行,每行3个数,op, a, b,(0 ≤ op ≤ 4,0 ≤ a ≤ b)

输出描述

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

示例1

输入

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

输出

5
2
6
5

备注

对于30%的数据, \(1\le n,m \le 1000\)
对于100%的数据, \(1\le n,m \le 10^5\)

题解

知识点:线段树。

这一道题维护的信息较多需要逐一分析。

为了方便求区间长度,还有取反的操作,我们将 \(0,1\) 的信息都维护一下,但接下来只讲 \(1\) 的部分, \(0\)\(1\) 就不讲了。

首先需要维护的是 \(1\) 的数量 \(sum1\) ,以及连续 \(1\) 个数的最大值 \(max1\)

在合并时, \(sum1\) 直接加即可。 \(max1\) 不仅要取子区间的 \(max1\) , 还需要考虑左子区间从右端点开始连续的 \(1\) ,以及右子区间从左端点开始连续的 \(1\) ,两部分拼起来的长度。因此还需要维护,区间从左端点开始连续 \(1\) 的个数 \(left1\) ,从右端点开始连续 \(1\) 的个数 \(right1\)

对于 \(left1,right1\) ,在合并时,要考虑一个特殊情况,左子区间 \(left1\) 等于区间长度(可用 \(sum0 + sum1\) 表示),那么他可以与右子区间的 \(left1\) 相加,得到区间的 \(left1\)\(right1\) 同理。除此之外,直接继承即可。

因此,区间信息需要维护 \(sum0/1,max0/1,left0/1,right0/1\)

区间修改需要维护三种修改标记:全 \(0\) 、全 \(1\) 、取反。三种的区间修改都十分好实现,前两种直接改为区间长度,取反交换 \(0/1\) 即可。另外,考虑到标记下传需要一个标记表示没有修改,即单位元值,以供函数特判。

因此,区间修改需要维护 \(0/1/2/3\) (无修改、全 \(0\) 、全 \(1\) 、取反)。

懒标记的修改需要分类讨论:

  1. 修改为未修改,则新标记维持原状。
  2. 修改为全 \(0\) ,则新标记为全 \(0\)
  3. 修改为全 \(1\) ,则新标记为全 \(1\)
  4. 修改为取反,则分类讨论:
    1. 若原标记为未修改,则新标记为取反。
    2. 若原标记为全 \(0\) ,则新标记为全 \(1\)
    3. 若原标记为全 \(1\) ,则新标记为全 \(0\)
    4. 若原标记为取反,则新标记为未修改。

于是所有信息就维护完了。

时间复杂度 \(O((n+m) \log n)\)

空间复杂度 \(O(n)\)文章来源地址https://www.toymoban.com/news/detail-431745.html

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    int sum0, sum1;
    int max0, max1;
    int left0, left1;
    int right0, right1;
    static T e() {
        return {
            0,0,
            0,0,
            0,0,
            0,0
        };
    }
    friend T operator+(const T &a, const T &b) {
        return{
            a.sum0 + b.sum0,a.sum1 + b.sum1,
            max({a.max0,b.max0,a.right0 + b.left0}),max({a.max1,b.max1,a.right1 + b.left1}),
            a.left0 == a.sum0 + a.sum1 ? a.left0 + b.left0 : a.left0,a.left1 == a.sum0 + a.sum1 ? a.left1 + b.left1 : a.left1,
            b.right0 == b.sum0 + b.sum1 ? b.right0 + a.right0 : b.right0,b.right1 == b.sum0 + b.sum1 ? b.right1 + a.right1 : b.right1
        };
    }
};
struct F {
    int op;
    static F e() { return{ 0 }; }
    T operator()(const T &x) {
        if (op == 0) return x;
        else if (op == 1) return {
            x.sum0 + x.sum1,0,
            x.sum0 + x.sum1,0,
            x.sum0 + x.sum1,0,
            x.sum0 + x.sum1,0
        };
        else if (op == 2) return{
            0,x.sum0 + x.sum1,
            0,x.sum0 + x.sum1,
            0,x.sum0 + x.sum1,
            0,x.sum0 + x.sum1
        };
        else return{
            x.sum1,x.sum0,
            x.max1,x.max0,
            x.left1,x.left0,
            x.right1,x.right0
        };
    }
    F operator() (const F &g) {
        if (op == 0) return g;
        else if (op == 1) return { 1 };
        else if (op == 2) return { 2 };
        else {
            if (g.op == 0) return { 3 };
            else if (g.op == 1) return { 2 };
            else if (g.op == 2) return { 1 };
            else return { 0 };
        }
    }
};

template<class T, class F>
class SegmentTreeLazy {
    int n;
    vector<T> node;
    vector<F> lazy;

    void push_down(int rt) {
        node[rt << 1] = lazy[rt](node[rt << 1]);
        lazy[rt << 1] = lazy[rt](lazy[rt << 1]);
        node[rt << 1 | 1] = lazy[rt](node[rt << 1 | 1]);
        lazy[rt << 1 | 1] = lazy[rt](lazy[rt << 1 | 1]);
        lazy[rt] = F::e();
    }

    void update(int rt, int l, int r, int x, int y, F f) {
        if (r < x || y < l) return;
        if (x <= l && r <= y) return node[rt] = f(node[rt]), lazy[rt] = f(lazy[rt]), void();
        push_down(rt);
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, y, f);
        update(rt << 1 | 1, mid + 1, r, x, y, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    T query(int rt, int l, int r, int x, int y) {
        if (r < x || y < l) return T::e();
        if (x <= l && r <= y) return node[rt];
        push_down(rt);
        int mid = l + r >> 1;
        return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
    }

public:
    SegmentTreeLazy(int _n = 0) { init(_n); }
    SegmentTreeLazy(int _n, const vector<T> &src) { init(_n, src); }
    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
        lazy.assign(n << 2, F::e());
    }
    void init(int _n, const vector<T> &src) {
        init(_n);
        function<void(int, int, int)> build = [&](int rt, int l, int r) {
            if (l == r) return node[rt] = src[l], void();
            int mid = l + r >> 1;
            build(rt << 1, l, mid);
            build(rt << 1 | 1, mid + 1, r);
            node[rt] = node[rt << 1] + node[rt << 1 | 1];
        };
        build(1, 1, n);
    }

    void update(int x, int y, const F &f) { update(1, 1, n, x, y, f); }

    T query(int x, int y) { return query(1, 1, n, x, y); }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<T> a(n + 1);
    for (int i = 1;i <= n;i++) {
        int x;
        cin >> x;
        a[i] = { 1 - x,x,1 - x,x,1 - x,x,1 - x,x };
    }
    SegmentTreeLazy<T, F> sgt(n, a);
    while (m--) {
        int op, l, r;
        cin >> op >> l >> r;
        l++, r++;
        if (op == 0) sgt.update(l, r, { 1 });
        else if (op == 1) sgt.update(l, r, { 2 });
        else if (op == 2) sgt.update(l, r, { 3 });
        else if (op == 3) cout << sgt.query(l, r).sum1 << '\n';
        else cout << sgt.query(l, r).max1 << '\n';
    }
    return 0;
}

到了这里,关于NC20279 [SCOI2010]序列操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 王道机试指南(第二版)——题目OJ链接

    王道机试指南(第二版)——题目OJ链接 方便大家跳转检验,侵删。 题目 地址 例题2.1 abc(清华大学复试上机题) 例题2.2 反序数(清华大学复试上机题) 例题2.3 对称平方数1(清华大学复试上机题) 习题2.1 与7无关的数(北京大学复试上机题) 习题2.2 百鸡问题(北京哈尔

    2024年01月17日
    浏览(47)
  • 数据结构学习记录——树习题—Tree Traversals Again(题目描述、输入输出示例、解题思路、解题方法C语言、解析)

    目录 题目描述 输入示例 输出示例 解题思路  解题方法(C语言) 解析 有序的二叉树遍历可以用堆栈以非递归的方式实现。 例如: 假设遍历一个节点数为6的二叉树(节点数据分别为1到6)时, 堆栈操作为:push(1);push(2);push(3);pop();pop();push(4);pop()

    2024年02月07日
    浏览(50)
  • 二叉树题目:二叉树的序列化与反序列化

    标题:二叉树的序列化与反序列化 出处:297. 二叉树的序列化与反序列化 8 级 要求 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原

    2024年01月23日
    浏览(44)
  • C++力扣题目491--非递减子序列

    力扣题目链接(opens new window) 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] 说明: 给定数组的长度不会超过15。 数组中的整数范围是 [-100,100]。

    2024年01月20日
    浏览(40)
  • PHP反序列化漏洞之产生原因(题目练习)

    PHP反序列化漏洞又叫做PHP对象注入漏洞,是因为程序对输入的序列化后的字符串处理不当导致的。反序列化漏洞的成因在于代码中的unserialize()接收参数可控,导致代码执行,SQL注入,目录遍历,getshell等后果。 一句话讲晒就是:  反序列化漏洞是由于unserialize函数接收到了

    2024年02月06日
    浏览(65)
  • 长春理工大学第六届CTF网络攻防大赛题解(文末有题目下载链接)

    此题解仅为部分题解,包括: 【RE】:①Reverse_Checkin ②SimplePE ③EzGame 【Web】①f12 ②ezrunner 【Crypto】①MD5 ②password ③看我回旋踢 ④摩丝 【Misc】①爆爆爆爆 ②凯撒大帝的三个秘密 ③你才是职业选手 ① Reverse Checkin: 双击文件看到如上提示:“也许你能从字符串里找到什么”

    2024年02月05日
    浏览(66)
  • 微信分享第三方连接(H5页面)自定义缩略图、标题、描述(显示分享框,而不是链接)(微信JS-SDK)

    首先要说明几个分享相关的问题: 现在微信不支持自定义按钮分享组件(也就是说不能点击某个按钮分享),只能通过微信右上角的三个小点,点击后选择分享给朋友,朋友圈等。 当前从企业微信分享到微信好友和微信朋友圈是有问题的,一些手机(有些是因为app版本,企

    2024年02月09日
    浏览(53)
  • 安装.net framework 4.0提示已是操作系统一部分但vs2010无法加载指定4.0版本的项目

     当vs2010加载项目出现这个情况时,因为win10操作系统已经有了.NET Framework 4.0,我们进入这个下载网站下载的安装包无法安装,有两个解决方法: 1.运行vs2010安装包选择修复 2.安装vs2019,在vs安装器中选择.NET Framework 4.0

    2024年01月16日
    浏览(53)
  • 操作系统2:进程的描述与控制

    目录 1、什么是前驱图? 2、进程的定义和描述 (1)什么是进程? (2)进程的基本状态及转换 (3)挂起操作和进程状态的转换 3、进程管理中的数据结构 (1)进程控制块 PCB 的作用 (2)进程控制块 PCB 中的信息 (3)PCB 的组织方式 3、进程的控制 (1)操作系统内核 (2)

    2024年02月09日
    浏览(39)
  • Win7环境64win操作系统,安装microsoft office2010 时MSXML版本6.10.1129.0,无法安装的解决办法

    ** 第一步 :在百度搜索MSXML6.10.1129.0软件进行下载,大概就是5M左右的大小,下载后解压,选择 第二项进行安装。 第二步: 按照https://mip.win7zhijia.cn/jiaocheng/win7_41377.html进行修改注册表。 但是往往按照以上步骤修改完注册表后还是不能正常安装。 原因是修改注册表时出错,如

    2024年02月12日
    浏览(75)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包