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

【线段树】P9349 [JOI 2023 Final] Stone Arranging 2|普及+

本文涉及知识点

C++线段树

P9349 [JOI 2023 Final] Stone Arranging 2

题目描述

JOI-kun has N N N go stones. The stones are numbered from 1 1 1 to N N N. The color of each stone is an integer between 1 1 1 and 1 0 9 10^9 109, inclusive. In the beginning, the color of Stone i i i ( 1 ≤ i ≤ N 1 \le i \le N 1iN) is A i A_i Ai.

From now, JOI-kun will perform N N N operations. He will put the stones on the table in a line. The operation i i i ( 1 ≤ i ≤ N 1 \le i \le N 1iN) will be performed as follows:

  1. JOI-kun will put Stone i i i on the immediate right of Stone i − 1 i - 1 i1. However, when i = 1 i = 1 i=1, JOI-kun will put Stone 1 on the table.
  2. If there is a stone among Stones 1 , 2 , ⋯ , i − 1 1,2,\cdots,i-1 1,2,,i1 whose current color is the same as Stone i i i, let j j j be the maximum index of such stones, and JOI-kun will paint all of Stones j + 1 , j + 2 , ⋯ , i − 1 j+1,j+2,\cdots,i-1 j+1,j+2,,i1 with the color A i A_i Ai.

In order to confirm whether the operations are correctly performed, JOI-kun wants to know in advance the colors of the stones after all the operations are performed.

Given information of the go stones, write a program which determines the colors of the stones after the N N N operations are performed.

输入格式

Read the following data from the standard input.

N N N
A 1 A_1 A1
A 2 A_2 A2
⋮ \vdots
A N A_N AN

输出格式

Write N N N lines to the standard output. The i i i-th line ( 1 ≤ i ≤ N 1 \le i \le N 1iN) should contain the color of Stone i i i after the N N N operations are performed.

输入输出样例 #1

输入 #1

6
1
2
1
2
3
2

输出 #1

1
1
1
2
2
2

输入输出样例 #2

输入 #2

10
1
1
2
2
1
2
2
1
1
2

输出 #2

1
1
1
1
1
1
1
1
1
2

说明/提示

Samples

Sample 1

The operations are performed as in the following table.

Finally, the colors of Stones 1, 2, 3, 4, 5, 6 will be 1, 1, 1, 2, 2, 2, respectively.

This sample input satisfies the constraints of Subtasks 1, 3.

Sample 2

This sample input satisfies the constraints of all the subtasks.

Constraints

  • 1 ≤ N ≤ 2 × 1 0 5 1 \le N \le 2\times 10^5 1N2×105.
  • 1 ≤ A i ≤ 1 0 9 1 \le A_i \le 10^9 1Ai109 ( 1 ≤ i ≤ N 1 \le i \le N 1iN).
  • Given values are all integers.

Subtasks

  1. (25 points) N ≤ 2000 N \le 2 000 N2000.
  2. (35 points) A i ≤ 2 A_i \le 2 Ai2 ( 1 ≤ i ≤ N 1 \le i \le N 1iN).
  3. (40 points) No additional constraints.

线段树

以下两个变量记录所有已经排列,且不属于任意a[j…i-1]的棋子。
unordered_map<int, vector> mColorIndexs; 键是颜色,值是下标,升序。
set inxs;下标。
线段树记录修改状态。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;scanf("%d", &n);vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 12 * 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;}inline void write(char ch){*m_p++ = ch;}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);}
private:char  puffer[N], * m_p;
};template<int N = 12 * 1'000'000>
class CInBuff
{
public:inline CInBuff() {fread(buffer, 1, N, stdin);}inline int Read() {int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);return f ? -x : x;}
private:char buffer[N], * S = buffer;
};template<class TSave, class TRecord >
class CRangUpdateLineTree
{
protected:virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) = 0;virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
};template<class TSave, class TRecord >
class CVectorRangeUpdateLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
public:CVectorRangeUpdateLineTree(int iEleSize, TSave tDefault, TRecord tRecordNull) :m_iEleSize(iEleSize), m_tDefault(tDefault), m_save(iEleSize * 4, tDefault), m_record(iEleSize * 4, tRecordNull) {m_recordNull = tRecordNull;}void Update(int iLeftIndex, int iRightIndex, TRecord value){Update(1, 0, m_iEleSize - 1, iLeftIndex, iRightIndex, value);}TSave Query(int leftIndex, int rightIndex) {return Query(leftIndex, rightIndex, m_tDefault);}TSave Query(int leftIndex, int rightIndex, const TSave& tDefault) {TSave ans = tDefault;Query(ans, 1, 0, m_iEleSize - 1, leftIndex, rightIndex);return ans;}//void Init() {//	Init(1, 0, m_iEleSize - 1);//}TSave QueryAll() {return m_save[1];}void swap(CVectorRangeUpdateLineTree<TSave, TRecord>& other) {m_save.swap(other.m_save);m_record.swap(other.m_record);std::swap(m_recordNull, other.m_recordNull);assert(m_iEleSize == other.m_iEleSize);}
protected://void Init(int iNodeNO, int iSaveLeft, int iSaveRight)//{//	if (iSaveLeft == iSaveRight) {//		this->OnInit(m_save[iNodeNO], iSaveLeft);//		return;//	}//	const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;//	Init(iNodeNO * 2, iSaveLeft, mid);//	Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);//	this->OnUpdateParent(m_save[iNodeNO], m_save[iNodeNO * 2], m_save[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);//}void Query(TSave& ans, int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {this->OnQuery(ans, m_save[iNodeNO], iSaveLeft, iSaveRight);return;}if (iSaveLeft == iSaveRight) {//没有子节点return;}Fresh(iNodeNO, iSaveLeft, iSaveRight);const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (mid >= iQueryLeft) {Query(ans, iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);}if (mid + 1 <= iQueryRight) {Query(ans, iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);}}void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value){if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight)){this->OnUpdate(m_save[iNode], iSaveLeft, iSaveRight, value);this->OnUpdateRecord(m_record[iNode], value);return;}if (iSaveLeft == iSaveRight) {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);}// 如果有后代,至少两个后代this->OnUpdateParent(m_save[iNode], m_save[iNode * 2], m_save[iNode * 2 + 1], iSaveLeft, iSaveRight);}void Fresh(int iNode, int iDataLeft, int iDataRight){if (m_recordNull == m_record[iNode]){return;}const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_record[iNode]);Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_record[iNode]);m_record[iNode] = m_recordNull;}vector<TSave> m_save;vector<TRecord> m_record;TRecord m_recordNull;TSave m_tDefault;const int m_iEleSize;
};template<class TSave, class TRecord >
class  CSetMaxLineTree : public CVectorRangeUpdateLineTree<TSave, TRecord>
{
public:using CVectorRangeUpdateLineTree<TSave, TRecord>::CVectorRangeUpdateLineTree;
protected:virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) {ans = max(ans, save);}virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) {save = update;}virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) {par = max(left, r);}virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord){old = newRecord;}
};class Solution {
public:vector<int> Ans(const vector<int>& a) {const int N = a.size();CSetMaxLineTree<int, int> lineTree(N, 0, 0);set<int> inxs;unordered_map<int, vector<int>> mColorIndexs;for (int i = 0; i < N; i++) {int j = i;if (mColorIndexs.count(a[i]) && mColorIndexs[a[i]].size()) {j = mColorIndexs[a[i]].back();};for (auto it = inxs.lower_bound(i);;) {if (inxs.begin() == it) { break; }--it;if (*it < j) { break; }mColorIndexs[a[*it]].pop_back();}inxs.erase(inxs.lower_bound(j), inxs.lower_bound(i));inxs.emplace(i);mColorIndexs[a[i]].emplace_back(i);lineTree.Update(j, i, a[i]);}vector<int> ans;for (int i = 0; i < N; i++) {ans.emplace_back(lineTree.Query(i, i));}return ans;}
};int main() {	
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	auto a = Read<int>();auto res = Solution().Ans(a);for (const auto& i : res) {cout << i << endl;}cout << endl;
#ifdef _DEBUG		/*printf("T=%d,", T);*/Out(a, "a=");
#endif // DEBUG	return 0;
}

单元测试

vector<int> a;TEST_METHOD(TestMethod11){a = {1,2};auto res = Solution().Ans(a);AssertV({1,2}, res);}TEST_METHOD(TestMethod12){a = { 1,2 ,1};auto res = Solution().Ans(a);AssertV({ 1,1,1 }, res);}TEST_METHOD(TestMethod13){a = { 4,1,2,3,2,1 };auto res = Solution().Ans(a);AssertV({4,1,1, 1,1,1 }, res);}TEST_METHOD(TestMethod14){a = { 1,2,1,2,3,2 };auto res = Solution().Ans(a);AssertV({ 1,1,1,2,2,2 }, res);}TEST_METHOD(TestMethod15){a = { 1,1,2,2,1,2,2,1,1,2 };auto res = Solution().Ans(a);AssertV({ 1,1,1,1,1,1,1,1,1,2 }, res);}

不用线段树

在inxs中存在的下标,颜色是原色,不存在的颜色就是inxs存在的后一个下标的颜色。
即:a[i] = *inxs.lower(i);

class Solution {public:vector<int> Ans(const vector<int>& a) {const int N = a.size();set<int> inxs;unordered_map<int, vector<int>> mColorIndexs;for (int i = 0; i < N; i++) {int j = i;if (mColorIndexs.count(a[i]) && mColorIndexs[a[i]].size()) {j = mColorIndexs[a[i]].back();};for (auto it = inxs.lower_bound(i);;) {if (inxs.begin() == it) { break; }--it;if (*it < j) { break; }mColorIndexs[a[*it]].pop_back();}inxs.erase(inxs.lower_bound(j), inxs.lower_bound(i));inxs.emplace(i);mColorIndexs[a[i]].emplace_back(i);					;}vector<int> ans;for (int i = 0; i < N; i++) {ans.emplace_back(a[*inxs.lower_bound(i)]);}return ans;}};

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

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

http://www.xdnf.cn/news/5726.html

相关文章:

  • 树莓5安装 PyCharm 进行python脚本开发
  • BFS算法篇——从晨曦到星辰,BFS算法在多源最短路径问题中的诗意航行(下)
  • hivesql是什么数据库?
  • Kafka Go客户端--Sarama
  • 离散制造企业WMS+MES+QMS+条码管理系统高保真原型全解析
  • Readiris PDF:高效文档管理与OCR识别工具
  • 百度智能云千帆携手联想,共创MCP生态宇宙
  • LabVIEW 编程难点
  • 《构建社交应用的安全结界:双框架对接审核API的底层逻辑与实践》
  • 绘制时间对应的数据曲线
  • [经验总结]删除gitlab仓库分支报错:错误:无法推送一些引用到“http:”
  • Kafka 如何保证消息顺序性
  • Open Source Geospatial Content Management System -GeoNode
  • webpack重构优化
  • 3d关键点 可视化
  • WPF的UI元素类型详解
  • 大容量存储的高性能 T-BOX 方案对智能网联汽车的支撑
  • 免费专业级 PDF 处理!SolidPDF OCR 识别 + 精准转换批量处理
  • Dinky 安装部署并配置提交 Flink Yarn 任务
  • 某实战项目登录口处的渗透测试
  • 运行Spark程序-在Spark-shell——RDD
  • #跟着若城学鸿蒙#HarmonyOS NEXT学习之Blank组件详解
  • 2025年01月10日浙江鑫越系统科技前端面试
  • 商业航天运动控制系统中的高可靠性芯片解决方案:挑战、策略与应用研究
  • Spark处理过程-转换算子
  • K8s 图形界面管理kubesphere
  • 遨游5G-A防爆手机:赋能工业通信更快、更安全
  • SAM论文学习
  • LVGL(lv_led LED灯控件)
  • 【ROS2】通信部署概述(以话题(Topic)通信为例)