【线段树】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 1≤i≤N) 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 1≤i≤N) will be performed as follows:
- JOI-kun will put Stone i i i on the immediate right of Stone i − 1 i - 1 i−1. However, when i = 1 i = 1 i=1, JOI-kun will put Stone 1 on the table.
- If there is a stone among Stones 1 , 2 , ⋯ , i − 1 1,2,\cdots,i-1 1,2,⋯,i−1 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,⋯,i−1 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 1≤i≤N) 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 1≤N≤2×105.
- 1 ≤ A i ≤ 1 0 9 1 \le A_i \le 10^9 1≤Ai≤109 ( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N).
- Given values are all integers.
Subtasks
- (25 points) N ≤ 2000 N \le 2 000 N≤2000.
- (35 points) A i ≤ 2 A_i \le 2 Ai≤2 ( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N).
- (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++**实现。
相关文章:

【线段树】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,…...
分别在windows和linux上使用curl,有啥区别?
作为开发者常用的网络工具,curl 在 Windows 和 Linux 上的使用看似相似,但实际存在不少细节差异。以下从 命令语法、环境特性、功能支持 和 开发体验 四个角度展开对比,帮助读者避免跨平台开发时的常见“坑”。 一、命令语法差异:…...

CodeBuddy终极测评:中国版Cursor的开发革命(含安装指南+HTML游戏实战)
一、腾讯云CodeBuddy产品全景解读 1. 什么是腾讯云代码助手? 官方定义: Tencent Cloud CodeBuddy是由腾讯自研的AI编程辅助工具,基于混元大模型DeepSeek双引擎,提供: ✅ 智能代码补全(支持200语言&#x…...

从数据中台到数据飞轮:实现数据驱动的升级之路
从数据中台到数据飞轮:实现数据驱动的升级之路 随着数字化转型的推进,数据已经成为企业最重要的资产之一,企业普遍搭建了数据中台,用于整合、管理和共享数据;然而,近年来,数据中台的风潮逐渐减退…...
机器学习第八讲:向量/矩阵 → 数据表格的数学表达,如Excel表格转数字阵列
机器学习第八讲:向量/矩阵 → 数据表格的数学表达,如Excel表格转数字阵列 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署:…...

8天Python从入门到精通【itheima】-1~5
目录 1节: 1.Python的优势: 2.Python的独具优势的特点: 2节-初识Python: 1.Python的起源 2.Python广泛的适用面: 3节-什么是编程语言: 1.编程语言的作用: 2.编程语言的好处:…...

T2000云腾边缘计算盒子在数猪场景中的应用|YOLOv8+NodeRED
在现代养猪业蓬勃发展的当下,养殖场的智能化管理成为提升效率与精准度的关键所在。而养猪场盘点工作一直是养殖场管理中的重要环节,传统的盘点方式不仅耗费大量人力、时间,还容易出现误差。如今,T2000 云腾边缘计算盒子的出现&…...

Baklib内容中台构建全攻略
内容中台构建路径全解析 企业构建内容中台需遵循“战略驱动-系统搭建-持续优化”的三阶段路径。首先明确业务目标与知识资产类型,通过显性知识结构化将分散内容转化为标准化数字资产,依托四库体系(知识库、资源库、模板库、规则库࿰…...
Spark的缓存
RDD缓存 Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或缓存多个数据集。当持久化某个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍生出的RDD进行的其他动作中重用。这使得后续的动作变得更加迅速。…...

爬虫工具与编程语言选择指南
有人问爬虫如何选择工具和编程语言。根据我多年的经验来说,是我肯定得先分析不同场景下适合的工具和语言。 如果大家不知道其他语言,比如JavaScript(Node.js)或者Go,这些在特定情况下可能更合适。比如,如果…...

系统平衡与企业挑战
在复杂的系统中,一切都在寻找平衡,而这个平衡从不静止。它在不断的变化与反馈中调整,以适应外界环境的变动。就像一个企业,它无法完全回避变化,但却总是在挑战中寻找新的平衡点。 最近遇到一家企业,引入了…...

征程 6 yolov5s-rgb-nhwc 量化指南
在 征程 6 平台,我们可以按照这个方式编译 input_typr_rt 为 rgb,且 layout 为 NHWC 的模型。这样做的好处是,当用户的数据输入源本身就是 NHWC 的 rgb 图像时,这么做可以避免额外的数据处理操作。这里以 yolov5s 为例进行介绍。 …...

国产化Word处理控件Spire.Doc教程:如何使用 C# 从 Word 中提取图片
通过编程方式从 Word 文档中提取图片,可以用于自动化文档处理任务。E-iceblue旗下Spire系列产品是国产文档处理领域的优秀产品,支持国产化,帮助企业高效构建文档处理的应用程序。本文将演示如何使用 C# 和 Spire.Doc for .NET 库从 Word 文件…...

Telnet 类图解析
Telnet 类图(文本描述) --------------------------------------- | Telnet | --------------------------------------- | - host: str | # 目标主机 | - port: int …...
Python之with语句
文章目录 Python中的with语句详解一、基本语法二、工作原理三、文件操作中的with语句1. 基本用法2. 同时打开多个文件 四、with语句的优势五、自定义上下文管理器1. 基于类的实现2. 使用contextlib模块 六、常见应用场景七、注意事项 Python中的with语句详解 with语句是Python…...
【Flask全栈开发指南】从零构建企业级Web应用
目录 🌟 前言🏗️ 技术背景与价值🚧 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🔍 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🧩 关键技术模块说明⚖️ 技术选…...
mac 10.15.7 svn安装
macOS 版本推荐 SVN 安装方式≤10.14Homebrew 安装独立 SVN≥10.15优先使用 CLT 自带 SVN 一、使用 brew 安装 (没成功) brew install subversion 这个方法安装一直不成功,一直在提示说版本旧或都是一些引用工具安装失败, 二、使…...

PowerShell 实现 conda 懒加载
问题 执行命令conda init powershell会在 profile.ps1中添加conda初始化的命令。 即使用户不需要用到conda,也会初始化conda环境,拖慢PowerShell的启动速度。 解决方案 本文展示了如何实现conda的懒加载,默认不加载conda环境,只…...

笔记项目 day02
一、用户登录接口 请求参数: 用loginDTO来封装请求参数,要加上RequestBody注解 响应参数: 由于data里内容较多,考虑将其封装到一个LoginUser的实体中,用户登陆后,需要生成jwtToken并返回给前端。 登录功…...
Memcached 服务搭建和集成使用的详细步骤示例
以下是 Memcached 服务搭建和集成使用的详细步骤示例: 一、搭建 Memcached 服务 安装 Memcached Linux 系统 yum 安装:执行命令 yum install -y memcached memcached-devel。源码安装 下载源码:wget http://www.memcached.org/files/memcach…...

国鑫主板bios切换显示模式为独立显卡
# 进入到Platform Miscellaneous Configuration Active Video 切换为PCIE Device保存退出! 如果之前有安装过nvidia驱动,记得卸载掉再安装一遍。...
嵌入式硬件篇---CAN
文章目录 前言1. CAN协议基础1.1 物理层特性差分信号线终端电阻通信速率总线拓扑 1.2 帧类型1.3 数据帧格式 2. STM32F103RCT6的CAN硬件配置2.1 硬件连接2.2 CubeMX配置启用CAN1模式波特率引脚分配过滤器配置(可选) 3. HAL库代码实现3.1 CAN初始化3.2 发…...

【日撸 Java 300行】Day 14(栈)
目录 Day 14:栈 一、栈的基本知识 二、栈的方法 1. 顺序表实现栈 2. 入栈 3. 出栈 三、代码及测试 拓展: 小结 Day 14:栈 Task: push 和 pop 均只能在栈顶操作.没有循环, 时间复杂度为 O(1). 一、栈的基本知识 详细的介…...

2025最新出版 Microsoft Project由入门到精通(七)
目录 优化资源——在资源使用状况视图中查看资源的负荷情况 在资源图表中查看资源的负荷情况 优化资源——资源出现冲突时的原因及处理办法 资源过度分类的处理解决办法 首先检查任务工时的合理性并调整 增加资源供给 回到资源工作表中双击对应的过度分配资源 替换资…...

修改(替换)文件中的指定内容并保留文件修改前的时间(即修改前后文件的最后修改时间保持不变)
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 修改(替换)文件中的指…...
Linux云计算训练营笔记day07(MySQL数据库)
数据库 DataBase 保存数据的仓库 数据库管理系统 DBMS 这是一个可以独立运行,用于维护磁盘上的数据的一套软件 特点: 维护性高,灵活度高,效率高,可扩展性强 常见的DBMS Mysql Mariadb Oracle DB2 SQLServer MySQL是一个关系型…...

应用探析|千眼狼PIV测量系统在职业病防治中的应用
1、职业病防治背景 随着《职业病防治法》及各省市“十四五”职业病防治规划的深入推进,工作场所粉尘危害监测与防控已成为疾控部门的核心任务。以矿山、建材、冶金、化工等行业为例,粉尘浓度、分布及传播特性的精准测量是评估职业病风险的关键。 传统的…...
获取accesstoken时,提示证书解析有问题,导致无法正常获取token
错误: https://qyapi.weixin.qq.com/cgi-bin/gettoken": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targ…...
面试中被问到谈谈你对threadlocal的理解
ThreadLocal 的核心理解 1. 基本概念 ThreadLocal 是 Java 提供的线程局部变量机制,用于在多线程环境中为每个线程维护独立的变量副本,实现线程隔离。其核心思想是空间换时间,通过避免共享变量带来的同步开销,提升并发性能。 2…...

nvidia驱动更新-先卸载再安装-ubuntu
显卡驱动升级前,卸载旧版本,可采用两种方式。 1.命令行 (1)查找已安装的 NVIDIA 驱动和相关包:dpkg -l | grep nvidia (2)完全卸载 NVIDIA 驱动:sudo apt remove purge nvidia-*…...