【线段树】1622. 奇妙序列

本文涉及知识点

设计 数学 线段树

本文基础解法

【设计】 【数学】1622 奇妙序列

LeetCode1622. 奇妙序列

请你实现三个 API append,addAll 和 multAll 来实现奇妙序列。
请实现 Fancy 类 :
Fancy() 初始化一个空序列对象。
void append(val) 将整数 val 添加在序列末尾。
void addAll(inc) 将所有序列中的现有数值都增加 inc 。
void multAll(m) 将序列中的所有现有数值都乘以整数 m 。
int getIndex(idx) 得到下标为 idx 处的数值(下标从 0 开始),并将结果对 109 + 7 取余。如果下标大于等于序列的长度,请返回 -1 。

示例:
输入:
[“Fancy”, “append”, “addAll”, “append”, “multAll”, “getIndex”, “addAll”, “append”, “multAll”, “getIndex”, “getIndex”, “getIndex”]
[[], [2], [3], [7], [2], [0], [3], [10], [2], [0], [1], [2]]
输出:
[null, null, null, null, null, 10, null, null, null, 26, 34, 20]

解释:
Fancy fancy = new Fancy();
fancy.append(2); // 奇妙序列:[2]
fancy.addAll(3); // 奇妙序列:[2+3] -> [5]
fancy.append(7); // 奇妙序列:[5, 7]
fancy.multAll(2); // 奇妙序列:[52, 72] -> [10, 14]
fancy.getIndex(0); // 返回 10
fancy.addAll(3); // 奇妙序列:[10+3, 14+3] -> [13, 17]
fancy.append(10); // 奇妙序列:[13, 17, 10]
fancy.multAll(2); // 奇妙序列:[132, 172, 10*2] -> [26, 34, 20]
fancy.getIndex(0); // 返回 26
fancy.getIndex(1); // 返回 34
fancy.getIndex(2); // 返回 20
提示:
1 <= val, inc, m <= 100
0 <= idx <= 105
总共最多会有 105 次对 append,addAll,multAll 和 getIndex 的调用。

线段树

由于最多105个元素,故线段树的元素个数105,初始全部为0。m_iSize记录已经插入的数据。
插入相当于对m_iSize单点更新(加法),乘和加相当于区域[0,m_iSize-1]更新。
std::pair记录更新的参数。first表示要乘的数,second 表示要加的数。两次操作合并的代码如下:

 virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override{old.first *= newRecord.first;old.second = old.second * newRecord.first + newRecord.second;}

推导过程x先乘以a,加b;在乘以c,加d。
x1 = ax +b
x2 = axc + bc + d
相当于:x直接乘以 ab 后加bc+d。

代码

核心代码

template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}bool operator==(const C1097Int& o)const{return m_iData == o.m_iData;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};template<class TSave, class TRecord>
class CLineTree
{
public:CLineTree(int iEleSize, TRecord recordNull=0):m_iEleSize(iEleSize), m_vArr(m_iEleSize * 4), m_vRecord(m_iEleSize * 4, recordNull), m_recordNull(recordNull){}void Update(int iLeftIndex, int iRightIndex, TRecord value){Update(1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1, value);}template<class TGet>void Query(const TGet& oGet, int iLeftIndex, int iRightIndex){Query(oGet, 1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1);}
private:virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) = 0;virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) = 0;template<class TGet>void Query(const TGet& oGet, int iNode, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight){if ((iQueryLeft <= iSaveLeft) && (iQueryRight >= iSaveRight)){oGet(m_vArr[iNode]);return;}Fresh(iNode, iSaveLeft, iSaveRight);const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (iMid >= iQueryLeft){Query(oGet, iNode * 2, iSaveLeft, iMid, iQueryLeft, iQueryRight);}if (iMid + 1 <= iQueryRight){Query(oGet, iNode * 2 + 1, iMid + 1, iSaveRight, iQueryLeft, iQueryRight);}}void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value){if (iNode >= m_vArr.size()){return;}if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight)){OnUpdate(m_vArr[iNode], min(iSaveRight, iOpeRight) - max(iSaveLeft, iOpeLeft) + 1, value);OnUpdateRecord(m_vRecord[iNode], value);return;}Fresh(iNode, iSaveLeft, iSaveRight);const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (iMid >= iOpeLeft){Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);}if (iMid + 1 <= iOpeRight){Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);}// 如果有后代,至少两个后代OnUpdateParent(m_vArr[iNode], m_vArr[iNode * 2], m_vArr[iNode * 2 + 1]);}void Fresh(int iNode, int iDataLeft, int iDataRight){if (m_recordNull == m_vRecord[iNode]){return;}const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_vRecord[iNode]);Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_vRecord[iNode]);m_vRecord[iNode] = m_recordNull;}const int m_iEleSize;vector<TSave> m_vArr;vector<TRecord> m_vRecord;const TRecord m_recordNull;
};template<class TSave = C1097Int<>, class TRecord = pair<C1097Int<>,C1097Int<>> >class CMyLineTree : public CLineTree<TSave, TRecord>{public:using CLineTree<TSave, TRecord>::CLineTree;	  protected:virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override{old.first *= newRecord.first;old.second = old.second * newRecord.first + newRecord.second;}virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) override{}virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) override{save = save * iUpdate.first + iUpdate.second;}};class Fancy {public:Fancy() :m_lineTree(100'000, { 1,0 }) {}void append(int val) {m_lineTree.Update(m_iSize, m_iSize, { 1,val });m_iSize++;}void addAll(int inc) {m_lineTree.Update(0, m_iSize - 1, { 1,inc });}void multAll(int m) {m_lineTree.Update(0, m_iSize - 1, { m,0 });}int getIndex(int idx) {if (idx >= m_iSize){return -1;}C1097Int<> iiRet = 0;auto Get = [&](const C1097Int<>& value ) {iiRet += value;};m_lineTree.Query(Get,idx,idx);return iiRet.ToInt();}CMyLineTree<> m_lineTree;int m_iSize=0;};

旧代码

旧类库,将TRecord 的默认值 设计成参数,编辑器对次有限制。改成成员变量。
template
class C1097Int
{
public:
C1097Int(long long llData = 0) :m_iData(llData% MOD)
{

}
C1097Int  operator+(const C1097Int& o)const
{return C1097Int(((long long)m_iData + o.m_iData) % MOD);
}
C1097Int& operator+=(const C1097Int& o)
{m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;
}
C1097Int& operator-=(const C1097Int& o)
{m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;
}
C1097Int  operator-(const C1097Int& o)
{return C1097Int((m_iData + MOD - o.m_iData) % MOD);
}
C1097Int  operator*(const C1097Int& o)const
{return((long long)m_iData * o.m_iData) % MOD;
}
C1097Int& operator*=(const C1097Int& o)
{m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;
}
bool operator<(const C1097Int& o)const
{return m_iData < o.m_iData;
}
C1097Int pow(long long n)const
{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;
}
C1097Int PowNegative1()const
{return pow(MOD - 2);
}
int ToInt()const
{return m_iData;
}

private:
int m_iData = 0;;
};
template<class TSave, class TRecord, TRecord RecordNull = 0>
class CLineTree
{
public:
CLineTree(int iEleSize)
:m_iEleSize(iEleSize), m_vArr(m_iEleSize * 4), m_vRecord(m_iEleSize * 4, RecordNull)
{

}
void Update(int iLeftIndex, int iRightIndex, TRecord value)
{Update(1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1, value);
}
template<class TGet>
void Query(const TGet& oGet, int iLeftIndex, int iRightIndex)
{Query(oGet, 1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1);
}

private:
virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) = 0;
virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) = 0;
template
void Query(const TGet& oGet, int iNode, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight)
{
if ((iQueryLeft <= iSaveLeft) && (iQueryRight >= iSaveRight))
{
oGet(m_vArr[iNode]);
return;
}
Fresh(iNode, iSaveLeft, iSaveRight);
const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
if (iMid >= iQueryLeft)
{
Query(oGet, iNode * 2, iSaveLeft, iMid, iQueryLeft, iQueryRight);
}
if (iMid + 1 <= iQueryRight)
{
Query(oGet, iNode * 2 + 1, iMid + 1, iSaveRight, iQueryLeft, iQueryRight);
}
}
void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value)
{
if (iNode >= m_vArr.size())
{
return;
}
if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
{
OnUpdate(m_vArr[iNode], min(iSaveRight, iOpeRight) - max(iSaveLeft, iOpeLeft) + 1, value);
OnUpdateRecord(m_vRecord[iNode], value);
return;
}
Fresh(iNode, iSaveLeft, iSaveRight);
const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
if (iMid >= iOpeLeft)
{
Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);
}
if (iMid + 1 <= iOpeRight)
{
Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);
}
// 如果有后代,至少两个后代
OnUpdateParent(m_vArr[iNode], m_vArr[iNode * 2], m_vArr[iNode * 2 + 1]);
}
void Fresh(int iNode, int iDataLeft, int iDataRight)
{
if (RecordNull == m_vRecord[iNode])
{
return;
}
const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_vRecord[iNode]);
Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_vRecord[iNode]);
m_vRecord[iNode] = RecordNull;
}
const int m_iEleSize;
vector m_vArr;
vector m_vRecord;
};
const long long llUnit = 2000’000’000;
template<class TSave = C1097Int<>, class TRecord = long long, TRecord RecordNull = llUnit >
class CMyLineTree : public CLineTree<TSave, TRecord, RecordNull>
{
public:
using CLineTree<TSave, TRecord, RecordNull>::CLineTree;
protected:
virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override
{
long long mul = (old/ llUnit) * (newRecord/ llUnit);
long long add = (old% llUnit) * (newRecord/ llUnit) + (newRecord% llUnit);
old = C1097Int<>(mul).ToInt()*llUnit + C1097Int<>(add).ToInt();
}
virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) override
{
}
virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) override
{
save = save * (iUpdate/ llUnit) + iUpdate% llUnit ;
}
};
class Fancy {
public:
Fancy():m_lineTree(100’000){
}
void append(int val) {
m_lineTree.Update(m_iSize, m_iSize, llUnit + val );
m_iSize++;
}
void addAll(int inc) {
m_lineTree.Update(0, m_iSize-1, llUnit + inc);
}
void multAll(int m) {
m_lineTree.Update(0, m_iSize - 1, llUnit *m);
}
int getIndex(int idx) {
if (idx >= m_iSize)
{
return -1;
}
C1097Int<> iiRet = 0;
auto Get = [&](const C1097Int<>& value ) {
iiRet += value;
};
m_lineTree.Query(Get,idx,idx);
return iiRet.ToInt();
}
CMyLineTree<> m_lineTree;
int m_iSize=0;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu下TexStudio如何兼容中文

怎么就想起来研究一下这个&#xff1f; 我使用大名鼎鼎的3Blue1Brown数学动画引擎Manim&#xff0c;制作了一个特别小的动画视频克里金插值。在视频中&#xff0c;绘制文字时&#xff0c;Manim使用到了texlive texlive-latex-extra这些库。专业的关系&#xff0c;当年的毕设没…

OKR管理模式:企业新引擎,驱动未来发展

在当今竞争激烈的市场环境中&#xff0c;越来越多的企业开始采用OKR&#xff08;Objectives and Key Results&#xff0c;目标与关键成果&#xff09;管理模式&#xff0c;以期解决一系列发展难题&#xff0c;驱动企业向前发展。OKR作为一种目标管理工具&#xff0c;旨在帮助企…

IT管理者需要熟知的思维模型

一、萨提亚冰山模型 萨提亚冰山模型是一种心理学概念,用来描述人类行为和情绪的本质和来源。它最早由心理学家弗洛伊德提出,被视为心理动力学理论的核心概念之一。该模型将人的心智分为三个层次:无意识、前意识和意识。无意识代表着个体无法直接意识到的心理内容,如欲望、冲…

python学习笔记——类

1. 类和对象**** 类、类属性、类方法不需要实例化就可以直接访问 实例相关&#xff0c;如实例属性、实例方法必须实例化后才可以访问 1.1. 类、类属性、实例属性、私有属性**** 1.1.1. 定义**** 类就是拥有相同属性和功能对象的集合 动物&#xff1a;猫、狗、鸡 人类&…

电动泡泡枪儿童电子方案

电动泡泡枪是一种娱乐装置&#xff0c;主要用于产生大量泡泡&#xff0c;通常在儿童游乐或各种庆典活动中使用。 这种装置通常由一个带有电机的手柄和位于一端的泡泡产生器组成。用户只需将泡泡液倒入产生器的容器中&#xff0c;启动设备后&#xff0c;内置的小型水泵会抽取泡…

[计算机知识] TCP/IP网络模型、MySQL的结构

TCP/IP网络模型 应用层 给用户提供应用功能&#xff0c;如HTTP, DNS 应用层处于用户态&#xff0c;传输层及以下处于内核态 传输层 给应用层提供网络支持&#xff0c;如TCP, UDP TCP提供稳定、面向连接的网络传输协议 应用层的数据可能会太大&#xff0c;就需要进行拆分…

关于Linux下的进程创建与终止(进程篇 - 涉及写时拷贝,fork函数)

目录 创建进程 写时拷贝 fork函数 进程终止 进程终止时&#xff0c;操作系统都做了什么&#xff1f; 进程终止的常见方式有哪些&#xff1f; 如何使用代码终止掉一个进程&#xff1f; 创建进程 写时拷贝 在了解下面的内容之前&#xff0c;我们需要先聊一聊写时拷贝这一…

渗透测试技巧总结67条

Tips 1. 手动端口探测 nmap的-sV可以探测出服务版本&#xff0c;但有些情况下必须手动探测去验证 使用Wireshark获取响应包未免大材小用&#xff0c;可通过nc简单判断 eg. 对于8001端口&#xff0c;nc连接上去&#xff0c;随便输入一个字符串&#xff0c;得到了以下结果&am…

制作framework

参考学习地址 https://www.jianshu.com/p/a15ad98bc965 注意事项&#xff1a; 1、在自动生成的.h文件中引入头文件时&#xff0c;需要完整路径 2、编译成功后如何查看位置 3、合并模拟器和真机 4、最后如何使用 合并并替换后&#xff0c;就把真机部分复制出来使用就行 5、…

实战搭建网易有道的QAnything(一) 前提准备工作

前言&#xff1a; 早上地铁上刷到了关于有道的QAnything的介绍&#xff0c;刚好也有搭建一个知识库的想法&#xff0c;既然有想法那就干起来&#xff0c;电脑的操作系统用的win11&#xff0c;显卡用了两块4060。 一、安装windows子系统 1. 开始-》运行-》控制面板 打开原始的控…

JS小项目-计算器

需求&#xff1a;根据素材制作如图所示页面&#xff0c;在页面输入第一个数和第二个数&#xff0c;单击&#xff08;加&#xff09;、&#xff0d;&#xff08;减&#xff09;、&#xff0a;&#xff08;乘&#xff09;、&#xff0f;&#xff08;除&#xff09;按钮时&#xf…

二 maven构建项目

一 Maven的GAVP Maven工程相对之前的工程&#xff0c;多出一组gavp属性&#xff0c;gav需要我们在创建项目的时指定&#xff0c;p有默认值&#xff0c;后期通过配置文件修改。 GAVP是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写&#xff0c;其中前三个是必…