「Codeforces」771-div2 E. Colorful Operations

news2024/9/22 13:44:54

E. Colorful Operations

https://codeforces.com/contest/1638/problem/E

题目描述

给你一个数组,默认初始元素为 0 ,颜色为 1,有三种操作:

  • Color l r c:将 [l, r] 区间内的颜色修改为 c
  • Add c x:将所有颜色为 c 的元素增加 x
  • Query i:打印第 i 个元素

输入描述

输入的第一行包含两个整数n和q(1≤n,q≤106) — 数组的长度以及您必须执行的查询次数。

接下来的每一个q行包含以问题陈述中描述的形式给出的查询。

输出描述

打印 Query 的结果。

样例

#1

5 8
Color 2 4 2
Add 2 2
Query 3
Color 4 5 3
Color 2 2 3
Add 3 3
Query 2
Query 5
2
5
3

#2

2 7
Add 1 7
Query 1
Add 2 4
Query 2
Color 1 1 1
Add 1 1
Query 2
7
7
8

提示

下面解释第一个样本测试。蓝色、红色和绿色分别代表颜色1,2和3。
1645166322574

解析

个人认为本题的难点主要是如何维护这个颜色,我一开始是想用一个结点内部维护一个 color 和 val 属性,表示每个结点的颜色和值,用的是线段树,后面我发现如果一个区间内的颜色不同,那么 color 到底应该填什么呢…,val 又表示啥呢?

当然,我这是普通的线段树模板而已,才学不久,看来还是我太菜了…

回到主题:

我们先考虑单点操作,三种操作如下:

  • Color x c:将元素 i 的颜色修改为 c
  • Add c x:将所有颜色为 c 的元素增加 x
  • Query i:打印第 i 个元素

首先我们需要一个 L a z y [ c o l o r ] Lazy[color] Lazy[color] 来保存每个颜色的总和,因为我们总不可能遍历每一个颜色为 c 的元素都增加 x 吧?这样效率很低,可以考虑先操作,等该数的颜色发生变化时,再去更新元素的值,这就是一个延迟操作的效果。

还需要一个 c o l o r [ i ] color[i] color[i] 保持元素 i 的颜色。

对于操作 2 来说: L a z y [ c ] + = x Lazy[c] += x Lazy[c]+=x

对于操作 3 来说: A [ x ] + L a z y [ c o l o r [ x ] ] A[x] + Lazy[color[x]] A[x]+Lazy[color[x]] (输出需要加上 Lazy ,这就是延迟)

对于操作 1 来说:

A [ x ] + = L a z y [ c o l o r [ x ] ] A[x] += Lazy[color[x]] A[x]+=Lazy[color[x]] (颜色准备发生改变,更新当前元素=>触发延迟操作)

c o l o r [ x ] = c color[x] = c color[x]=c (更新颜色)

A [ x ] − = L a z y [ c ] A[x] -= Lazy[c] A[x]=Lazy[c] (因为我们输出时,我们要保证 A [ x ] + L a z y [ c o l o r [ x ] ] A[x] + Lazy[color[x]] A[x]+Lazy[color[x]] ,因此需要减去 L a z y [ c ] Lazy[c] Lazy[c]

手动模拟一下:

【1】Add 1 7
【2】Query 1 7
【3】Add 2 4
【4】Query 2
【5】Color 1 2
【6】Query 1

====================
Lazy:  0 0 0
Color: 1 1 1
A:     0 0 0
====================
【1】Lazy[1] += 7
====================
Lazy:  7 0 0
Color: 1 1 1
A:     0 0 0
====================
【2】A[1] + Lazy[color[1]] // print 7
【3】Lazy[2] += 4
====================
Lazy:  7 4 0
Color: 1 1 1
A:     0 0 0
====================
【4】A[2] + Lazy[color[2]] // print 7
【5】A[1] += Lazy[color[1]]
     color[1] = 2
     A[1] -= Lazy[2]
====================
Lazy:  7 4 0
Color: 1 1 1
A:     7 0 0
--------------------
Lazy:  7 4 0
Color: 2 1 1
A:     7 0 0
--------------------
Lazy:  7 4 0
Color: 2 1 1
A:     3 0 0
====================
【6】A[1] + Lazy[color[1]] // print 7

明白了单点操作,回来看看区间操作:

采用线段树和LazyTag的方式来进行实现。

colorVal[color]:同上面的 Lazy

需要一个结点,里面维护如下元素:

  • same:该区间的所有元素是否相同
  • color:该结点的颜色,当 same 为 true 时,表示该区间内所有的颜色
  • lazy:懒标记,同时也作为该元素的值

对于操作 2 和 操作 3 来说,其实和单点的是一样。对于操作 1 来说也差不多。

对于操作 1:只修改同一种颜色的区间,否则就一定往下找,最后一个点一定为 true

AC Code

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));

    static final int MAX = 1000005;
    static long[] colorVal = new long[MAX];
    static Node[] T = new Node[MAX << 2];
    static int n, m;

    public static void main(String[] args) throws Exception {
        n = nextInt(); m = nextInt();
        build(1, 1, n);
        while(m-- != 0) {
            String opt = nextStr();
            if(opt.equals("Color")) update(1, nextInt(), nextInt(), nextInt());
            else if(opt.equals("Add")) colorVal[nextInt()] += nextInt();
            else if(opt.equals("Query")) {
                int v = nextInt();
                out.println(query(1, v, v));
            }
        }
        out.flush();
    }

    public static void build(int p, int start, int end) {
        T[p] = new Node(start, end);
        if(start == end) {
            T[p].color = 1;
            T[p].same = true;
            return;
        }
        int mid = (start + end) / 2;
        build(L(p), start, mid);
        build(R(p), mid + 1, end);
        pushUp(p);
    }

    public static void update(int p, int start, int end, int k) {
        // 只修改同一种颜色的区间,否则就一直往下找,最后一个点一定为 true
        if(start <= T[p].left && end >= T[p].right && T[p].same) {
            T[p].lazy += colorVal[T[p].color];
            T[p].color = k;
            T[p].lazy -= colorVal[T[p].color];
            return;
        }
        pushDown(p);
        int mid = (T[p].left + T[p].right) / 2;
        if(start <= mid) update(L(p), start, end, k);
        if(end > mid) update(R(p), start, end, k);
        pushUp(p);
    }

    public static long query(int p, int start, int end) {
        long res = 0;
        if(start <= T[p].left && end >= T[p].right)
            return T[p].lazy + colorVal[T[p].color];
        pushDown(p);
        int mid = (T[p].left + T[p].right) / 2;
        if(start <= mid) res += query(L(p), start, end);
        if(end > mid) res += query(R(p), start, end);
        return res;
    }

    public static void pushDown(int p) {
        // 因为我们修改的是同一种颜色的区间,因此也对同一种颜色的区间下传
        if(T[p].same) {
            T[L(p)].lazy += T[p].lazy;
            T[R(p)].lazy += T[p].lazy;
            T[L(p)].color = T[p].color;
            T[R(p)].color = T[p].color;
            T[p].lazy = 0;
        }
    }

    public static void pushUp(int p) {
        // 只更新同一种颜色的区间
        if(T[L(p)].same && T[R(p)].same && T[L(p)].color == T[R(p)].color) {
            T[p].same = true;
            T[p].color = T[R(p)].color;
        } else {
            T[p].same = false;
        }
    }

    public static int L(int p) { return p<<1; };
    public static int R(int p) { return p<<1|1; };

    public static int nextInt() throws Exception {
        st.nextToken();
        return (int) st.nval;
    }

    public static String nextStr() throws Exception {
        st.nextToken();
        return st.sval;
    }
}

class Node {
    int left, right;
    int color; // 该区间颜色
    long lazy; // lazyTag
    boolean same; // 该区间内的颜色是否完全相同
    public Node(int left, int right) {
        this.left = left;
        this.right = right;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Human Pose as Compositional Tokens 阅读笔记

人体姿态作为合成 token —— CVPR2023 论文链接 代码链接 摘要&#xff1a; 人体姿态常由身体关节的坐标向量或其热图embedding表示。虽然数据易于处理&#xff0c;但由于身体关节间缺乏依赖建模&#xff0c;即使是不现实的姿态也被接受。本文提出了一种结构化表示&#xff1…

el-form-renderer 使用指南

目录 前言 起步 使用 update-form && getFormValue 表单项动态显示或隐藏(hidden) 表单数据联动(on) 输入/输出格式化(inputFormat/outputFormat) set-options el-form-renderer 实践案例 案例一 案例二 自定义组件接入指南 前言 el-form-renderer是基于e…

Starting Windows PowerShell (启动 Windows PowerShell)

Starting Windows PowerShell (启动 Windows PowerShell) Windows PowerShell is a scripting engine .DLL that’s embedded into multiple hosts. The most common hosts you’ll start are the interactive command-line powershell.exe and the Interactive Scripting Envi…

【Java笔试强训 26】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;跳台阶扩…

Redis`数据结构`与`对象`概述

文章目录 Redis数据结构与对象概述一、数据结构1、简单动态字符串&#xff08;SDS&#xff09;SDS结构体定义SDS结构示意图使用SDS的五个优点 2、双端链表&#xff08;list&#xff09;链表结构体定义list结构示意图 3、字典&#xff08;dict&#xff09;字典结构体定义dict结构…

想要成为 NLP 领域的大牛?从 ChatGPT 的 5 大自然语言模型开始了解吧(LM、Transformer、GPT、RLHF、LLM)——小白也能看得懂

目录 前言ChatGPT基础科普——知其一点所以然1. LM2. Transformer3. GPT4. RLHF5. LLM 参考资料其它资料下载 前言 如果想在自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;领域内脱颖而出&#xff0c;那么你一定不能错过 ChatGPT 的 5 大自然…

软件设计师笔记

软件设计师笔记 计算机组成与体系结构 数据的表示、计算机结构、Flynn分类法、CISC与RISC、流水线技术、存储系统、总线系统、可靠性、校验码 1. 数据的表示 &#xff08;一&#xff09;进制转换 R进制转十进制使用按权展开法&#xff1a; 十进制转R进制使用短除法 二进制…

Python——狂肝两万字带你学会【类与对象】

目录 01-初始对象 生活中的数据组织 程序中的数据组织​ 使用对象组织数据 总结01 02-类的成员方法 类的定义和使用 成员变量和成员方法 成员方法的定义语法 注意事项 成员方法——代码演示 总结02 03-类和对象 现实世界的事物和类 类和对象 使用类和对象描述…

Java 基础进阶篇(三)—— 权限修饰符、final 关键字与枚举

文章目录 一、权限修饰符二、final 关键字2.1 final 作用2.2 final 修饰变量举例2.3 常量 三、枚举3.1 枚举的格式3.2 枚举的特征3.3 枚举的应用 一、权限修饰符 权限修饰符 用于约束成员变量、构造器、方法等的访问范围。 权限修饰符&#xff1a; 有四种作用范围由小到大 (p…

vue+element 多选级联选择器自定义props

前言 我这里分享的是Cascader 级联选择器中的多选、以及如何自定义props的使用详解 1.使用Cascader 级联选择器 效果 代码 <div class"block"><span class"demonstration">默认显示所有Tag</span><el-cascader:options"op…

Vue电商项目--vuex模块开发

vuex状态管理库 vuex是什么&#xff1f; vuex是官方提供的一个插件&#xff0c;状态管理库&#xff0c;集中式管理项目中组件共有的数据。 切记&#xff0c;并不是全部的项目都需要Vuex,如果项目很小&#xff0c;完全不需要vuex,如果项目很大&#xff0c;组件很多&#xff0…

一道Python初学者常犯错误解析

1. 引言 在Python学习中&#xff0c;经常会遇到各种各样的代码错误&#xff0c;尤其对于初学者而言&#xff0c;明明觉得逻辑上是对的&#xff0c;但是代码运行起来&#xff0c;往往不是自己想要的结果。 本文就最近在某平台看到的一个常见错误进行展开&#xff0c;帮助大家更…

06 虚拟化Open vSwitch环境部署

文章目录 06 虚拟化Open vSwitch环境部署6.1 安装Open vSwitch网桥6.1.1 安装Open vSwitch组件6.1.1.1 安装Open vSwitch组件6.1.1.2 启动Open vSwitch服务6.1.1.3 设置Open vSwitch服务随系统自动启动 6.1.2 确认安装是否成功6.1.2.1确认 Open vSwitch组件是否安装成功6.1.2.2…

kill 信号

kill -0 PidNum 参数是0&#xff0c;不会发送任何的信号&#xff0c;不会关闭程序&#xff0c;但会执行错误检查&#xff0c;对程序运行状态进行监控。可以用他来检测某个进程ID或进程组ID是否存在。从理解上看&#xff0c;作用相当于ps -p 。 进程已停止、不存在或其他异…

前端小白是如何利用chatgt用一周时间从做一款微信小程序的

前端小白是如何利用chatgt用一周时间从0做一款微信小程序的 随着chatgpt的大火&#xff0c;真的是在工作上给各行各业的人带来了极大的便利&#xff0c;本人是一个java程序员&#xff0c;其实我自己是一直想开发一款属于自己的小程序的&#xff0c;但是迫于对前端知识的贫瘠&a…

【五一创作】VimPlug插件配置

目录 Install Question Q1&#xff1a;字体乱码 Q2&#xff1a;插件配置 Q3&#xff1a;安装扩展插件 Q4&#xff1a;查看安装插件状态 Q5&#xff1a;查看默认插件 Q6&#xff1a;卸载插件 Q7&#xff1a;增加用户配置 Install Github地址&#xff1a;GitHub - chxu…

内网渗透之横向移动NTMLRelay(中继)攻击-InveighNTLM-Relay重放

横向移动 NTLM中继攻击 Relay重放(smb) 适用于无法获取hash或密码时使用 NTML Relay重放包括smb to relay ldap ews webserver: 执行下面的命令时会默认以当前用户名和密码去登录目标计算机 dir \\ 192.168.3.32\c$webserver切换到本地的administrator时 dir \\ 192.168.3.3…

权限提升:令牌窃取 || 进程注入.

权限提升&#xff1a;令牌窃取 || 进程注入. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因…

管理系统的实现_03

文章目录 登录界面的开发安装axios用于前后端交互第一步、在项目目录下执行命令第二步、在main.js文件夹添加如下代码第三步、使用this.axios 即可访问到 Login.vue 完整代码如下搭建第一个springboot项目第一步、修改配置文件(application.properties)第二步、创建包目录 用sp…

希尔排序(C++)

希尔排序 是插入排序的一种&#xff0c;也是缩小增量排序。希尔排序是记录按下标的一定增量分组&#xff0c;对每组使用直接插入排序算法排序&#xff1b;随着增量逐渐减少&#xff0c;每组包含的关键词越来越多&#xff0c;当增量减至1时&#xff0c;整个文件恰被分成一组&am…