当前位置: 首页 > news >正文

《P2572 [SCOI2010] 序列操作》

题目描述

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

  • 0 l r 把 [l,r] 区间内的所有数全变成 0;
  • 1 l r 把 [l,r] 区间内的所有数全变成 1;
  • 2 l r 把 [l,r] 区间内的所有数全部取反,也就是说把所有的 0 变成 1,把所有的 1 变成 0;
  • 3 l r 询问 [l,r] 区间内总共有多少个 1;
  • 4 l r 询问 [l,r] 区间内最多有多少个连续的 1。

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

输入格式

第一行两个正整数 n,m,表示序列长度与操作个数。
第二行包括 n 个数,表示序列的初始状态。
接下来 m 行,每行三个整数,表示一次操作。

输出格式

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

输入输出样例

输入 #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

输出 #1复制

5
2
6
5

说明/提示

【数据范围】
对于 30% 的数据,1≤n,m≤1000;
对于100% 的数据,1≤n,m≤105。

代码实现:

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

const int MAXN = 1e5 + 5;

// 线段树节点结构
struct Node {
    int l, r;         // 区间左右端点
    int sum;          // 区间内1的个数
    int max_len;      // 区间内最长连续1长度
    int l_max;        // 从左端点开始的最长连续1长度
    int r_max;        // 从右端点开始的最长连续1长度
    int tag0, tag1;   // 置0、置1标记
    int tag2;         // 取反标记
} tree[MAXN << 2];  // 线段树数组,大小通常为4*MAXN

int arr[MAXN];      // 原始数组

// 向上合并信息
void push_up(int p) {
    // 合并左右子节点信息
    tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
    
    // 计算最长连续1长度
    tree[p].l_max = tree[p<<1].l_max;
    if (tree[p<<1].l_max == tree[p<<1].r - tree[p<<1].l + 1) {
        tree[p].l_max += tree[p<<1|1].l_max;
    }
    
    tree[p].r_max = tree[p<<1|1].r_max;
    if (tree[p<<1|1].r_max == tree[p<<1|1].r - tree[p<<1|1].l + 1) {
        tree[p].r_max += tree[p<<1].r_max;
    }
    
    tree[p].max_len = max(max(tree[p<<1].max_len, tree[p<<1|1].max_len), 
                         tree[p<<1].r_max + tree[p<<1|1].l_max);
}

// 向下传递标记
void push_down(int p) {
    int l = p << 1, r = p << 1 | 1;
    int mid = (tree[p].l + tree[p].r) >> 1;
    
    // 处理置0标记
    if (tree[p].tag0) {
        tree[l].sum = 0;
        tree[l].max_len = tree[l].l_max = tree[l].r_max = 0;
        tree[l].tag0 = 1;
        tree[l].tag1 = tree[l].tag2 = 0;
        
        tree[r].sum = 0;
        tree[r].max_len = tree[r].l_max = tree[r].r_max = 0;
        tree[r].tag0 = 1;
        tree[r].tag1 = tree[r].tag2 = 0;
        
        tree[p].tag0 = 0;
    }
    
    // 处理置1标记
    if (tree[p].tag1) {
        tree[l].sum = mid - tree[l].l + 1;
        tree[l].max_len = tree[l].l_max = tree[l].r_max = mid - tree[l].l + 1;
        tree[l].tag1 = 1;
        tree[l].tag0 = tree[l].tag2 = 0;
        
        tree[r].sum = tree[r].r - mid;
        tree[r].max_len = tree[r].l_max = tree[r].r_max = tree[r].r - mid;
        tree[r].tag1 = 1;
        tree[r].tag0 = tree[r].tag2 = 0;
        
        tree[p].tag1 = 0;
    }
    
    // 处理取反标记
    if (tree[p].tag2) {
        // 交换0和1的数量
        tree[l].sum = (mid - tree[l].l + 1) - tree[l].sum;
        
        // 交换最长连续长度
        int temp = tree[l].max_len;
        tree[l].max_len = (mid - tree[l].l + 1) - temp;
        temp = tree[l].l_max;
        tree[l].l_max = (mid - tree[l].l + 1) - temp;
        temp = tree[l].r_max;
        tree[l].r_max = (mid - tree[l].l + 1) - temp;
        
        // 取反标记取反
        tree[l].tag2 ^= 1;
        swap(tree[l].tag0, tree[l].tag1);
        
        // 处理右子树
        tree[r].sum = (tree[r].r - mid) - tree[r].sum;
        
        temp = tree[r].max_len;
        tree[r].max_len = (tree[r].r - mid) - temp;
        temp = tree[r].l_max;
        tree[r].l_max = (tree[r].r - mid) - temp;
        temp = tree[r].r_max;
        tree[r].r_max = (tree[r].r - mid) - temp;
        
        tree[r].tag2 ^= 1;
        swap(tree[r].tag0, tree[r].tag1);
        
        tree[p].tag2 = 0;
    }
}

// 构建线段树
void build(int p, int l, int r) {
    tree[p].l = l;
    tree[p].r = r;
    tree[p].tag0 = tree[p].tag1 = tree[p].tag2 = 0;
    
    if (l == r) {
        tree[p].sum = arr[l];
        tree[p].max_len = tree[p].l_max = tree[p].r_max = arr[l];
        return;
    }
    
    int mid = (l + r) >> 1;
    build(p<<1, l, mid);
    build(p<<1|1, mid+1, r);
    push_up(p);
}

// 区间置0操作
void update0(int p, int l, int r) {
    if (tree[p].l >= l && tree[p].r <= r) {
        tree[p].sum = 0;
        tree[p].max_len = tree[p].l_max = tree[p].r_max = 0;
        tree[p].tag0 = 1;
        tree[p].tag1 = tree[p].tag2 = 0;
        return;
    }
    
    push_down(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if (l <= mid) update0(p<<1, l, r);
    if (r > mid) update0(p<<1|1, l, r);
    push_up(p);
}

// 区间置1操作
void update1(int p, int l, int r) {
    if (tree[p].l >= l && tree[p].r <= r) {
        tree[p].sum = tree[p].r - tree[p].l + 1;
        tree[p].max_len = tree[p].l_max = tree[p].r_max = tree[p].r - tree[p].l + 1;
        tree[p].tag1 = 1;
        tree[p].tag0 = tree[p].tag2 = 0;
        return;
    }
    
    push_down(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if (l <= mid) update1(p<<1, l, r);
    if (r > mid) update1(p<<1|1, l, r);
    push_up(p);
}

// 区间取反操作
void update2(int p, int l, int r) {
    if (tree[p].l >= l && tree[p].r <= r) {
        // 交换0和1的数量
        tree[p].sum = (tree[p].r - tree[p].l + 1) - tree[p].sum;
        
        // 交换最长连续长度
        int len = tree[p].r - tree[p].l + 1;
        int temp = tree[p].max_len;
        tree[p].max_len = len - temp;
        temp = tree[p].l_max;
        tree[p].l_max = len - temp;
        temp = tree[p].r_max;
        tree[p].r_max = len - temp;
        
        // 取反标记取反
        tree[p].tag2 ^= 1;
        swap(tree[p].tag0, tree[p].tag1);
        return;
    }
    
    push_down(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if (l <= mid) update2(p<<1, l, r);
    if (r > mid) update2(p<<1|1, l, r);
    push_up(p);
}

// 查询区间1的个数
int query3(int p, int l, int r) {
    if (tree[p].l >= l && tree[p].r <= r) {
        return tree[p].sum;
    }
    
    push_down(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    int res = 0;
    if (l <= mid) res += query3(p<<1, l, r);
    if (r > mid) res += query3(p<<1|1, l, r);
    return res;
}

// 查询区间最长连续1长度
int query4(int p, int l, int r) {
    if (tree[p].l >= l && tree[p].r <= r) {
        return tree[p].max_len;
    }
    
    push_down(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    
    // 如果查询区间完全在左子树或右子树
    if (r <= mid) return query4(p<<1, l, r);
    if (l > mid) return query4(p<<1|1, l, r);
    
    // 否则需要考虑跨越中点的情况
    int left_res = query4(p<<1, l, mid);
    int right_res = query4(p<<1|1, mid+1, r);
    
    // 计算跨越中点的连续1长度
    int cross_len = min(tree[p<<1].r_max, mid - l + 1) + 
                    min(tree[p<<1|1].l_max, r - (mid+1) + 1);
    
    return max(max(left_res, right_res), cross_len);
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }
    
    build(1, 0, n-1);
    
    while (m--) {
        int op, l, r;
        scanf("%d%d%d", &op, &l, &r);
        
        if (op == 0) {
            update0(1, l, r);
        } else if (op == 1) {
            update1(1, l, r);
        } else if (op == 2) {
            update2(1, l, r);
        } else if (op == 3) {
            printf("%d\n", query3(1, l, r));
        } else if (op == 4) {
            printf("%d\n", query4(1, l, r));
        }
    }
    
    return 0;
}

http://www.lryc.cn/news/579333.html

相关文章:

  • maker-pdf 文档文字识别,并用python实现
  • 专题:2025即时零售与各类人群消费行为洞察报告|附400+份报告PDF、原数据表汇总下载
  • 2025年6月:技术探索与生活平衡的协奏曲
  • 从零开始构建Airbyte数据管道:PostgreSQL到BigQuery实战指南
  • 基于定制开发开源AI智能名片与S2B2C商城小程序的搜索区用户需求洞察与精准服务研究
  • WebRTC 安全性分析研究
  • C# 线程同步(一)同步概念介绍
  • 网络安全的未来趋势与挑战
  • 好用的自带AI功能的国产IDE
  • Java-63 深入浅出 分布式服务 网络通信 RPC 与 RMI 详解
  • Spring 为何需要三级缓存解决循环依赖,而不是二级缓存
  • 【网络安全】Webshell命令执行失败解决思路
  • 【第十一篇】SpringBoot缓存技术
  • Javaweb - 10.1 Servlet
  • C盘空间的“元凶”——虚拟内存的神秘面纱
  • css ::before学习笔记
  • 专业AI工具导航与人工智能学习平台AIbase.cn 连接现在与AI未来的智能桥梁
  • YOLO基础算法入门之YOLOv8中的C2f(C2-Faster)高效特征提取结构
  • STC8G 8051内核单片机开发 (中断)
  • 算法学习笔记:4.KMP 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 家政维修小程序源码php方案解析
  • FASTAPI+VUE3平价商贸管理系统
  • 实际开发如何快速定位和解决死锁?
  • thinkphp中间件
  • 协同过滤推荐算法
  • 动态规划-P1216 [IOI 1994] 数字三角形 Number Triangles
  • RAG实战指南 Day 4:LlamaIndex框架实战指南
  • AutoMedPrompt的技术,自动优化提示词
  • 基于 govaluate 的监控系统中,如何设计灵活可扩展的自定义表达式函数体系
  • 【学习线路】机器学习线路概述与内容关键点说明