Substring of Sorted String 题解
写篇题解纪念一下蒟蒻第一次赛时切出的 F 题。
题目简述
对一个字符串进行单点修改,区间判断操作。
修改操作为将一个字符修改为另一个,判断操作为判断区间是否是整个字符串升序排序后的字串。
思路分析
蒟蒻第一眼线段树,但刚开始没仔细看题,以为是判断区间是否升序排序,所以很快得到做法:
对于每个线段树上的节点,保存三个信息:区间最左端的字符 \(\text{lz}\),区间最右端的字符 \(\text{rz}\),区间是否升序排序 \(\text{is}\)。
合并时,我们按照如下方法合并:(记整个区间的编号为 \(\text{p}\),左区间的编号为 \(\text{lson}\),右区间的编号为 \(\text{rson}\)。)
lz[p]=lz[lson]
rz[p]=rz[rson]
is[p]=is[lson]&&is[rson]&&(rz[lson]<=ls[rson])
至于为什么这样合并是显然的。
但在蒟蒻写完交了一发后,发现 WA 了,仔细看题后发现是判断区间是否是整个字符串是否是整个字符串升序排序后的字串。
但在思考后,蒟蒻得到了一个做法:
在每个节点上额外维护一个数组 \(\text{cnt}\),\(\text{cnt}[i]\) 表示在这个整个区间内第 \(i\) 个小写字母出现的个数,合并时只需要对于枚举每一个字符相加就行。
在判断时,我们在升序排序的基础上,判断这个区间内除了最左端字符和最右端字符之外的字符出现次数是否等于整个字符串的该字符出现次数就可以了,这样是可以保证没有问题的。
时间复杂度为 \(O(26q\log n)\),虽然常数比 \(\log\) 还大,但不影响正确性。
注意事项
单点修改后记得将之前的位置清零。
注意下标的同步。
代码
放上丑陋的赛时代码:
#include <bits/stdc++.h>
using namespace std;
const int N=100100;
int n,q,op,in1,in3;
char inp[N];//整个字符串
char in2[2];//输入的操作类型
struct STn{int l,r,is;char lz,rz;int cnt[30];};//线段树的节点
void merge(STn &res,STn a,STn b){//合并区间
res.lz=a.lz;
res.rz=b.rz;
res.is=(a.is&&b.is)&&(a.rz<=b.lz);//更新
for(int i=1;i<=26;i++)
res.cnt[i]=a.cnt[i]+b.cnt[i];//相加
}
struct ST{
STn a[N<<2];
void build(int p,int l,int r){
a[p].l=l;a[p].r=r;
if(a[p].l==a[p].r){a[p].lz=a[p].rz=inp[a[p].l];a[p].is=1;a[p].cnt[inp[a[p].l]-'a'+1]=1;return ;}//初始化
int mid=(a[p].l+a[p].r)>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
merge(a[p],a[p<<1],a[p<<1|1]);return ;
}
void change(int p,int x,char k){
if(a[p].l==a[p].r){a[p].cnt[a[p].lz-'a'+1]=0;a[p].lz=a[p].rz=k;a[p].cnt[k-'a'+1]=1;return ;}//单点修改后重置
int mid=(a[p].l+a[p].r)>>1;
if(x<=mid) change(p<<1,x,k);else change(p<<1|1,x,k);
merge(a[p],a[p<<1],a[p<<1|1]);return ;
}
STn ask(int p,int l,int r){
if(l<=a[p].l&&a[p].r<=r) return a[p];
int mid=(a[p].l+a[p].r)>>1;
if(r<=mid) return ask(p<<1,l,r);
if(l>mid) return ask(p<<1|1,l,r);
STn res;merge(res,ask(p<<1,l,r),ask(p<<1|1,l,r));//询问合并
return res;
}
}tree;
int main(){
scanf("%d",&n);
scanf("%s",inp+1);
scanf("%d",&q);
tree.build(1,1,n);
while(q--){
scanf("%d",&op);
if(op==1){scanf("%d%s",&in1,in2+1);tree.change(1,in1,in2[1]);}
if(op==2){
scanf("%d%d",&in1,&in3);
STn res=tree.ask(1,in1,in3);
if(res.is){//前提是区间升序排序
int f=1;
for(int i=res.lz+1;i<=res.rz-1;i++)
if(res.cnt[i-'a'+1]!=tree.a[1].cnt[i-'a'+1]){//tree.a[1]就是整个字符串
f=0;break;
} //判断字符出现次数
puts(f?"Yes":"No");
}
else puts("No");
}
}
return 0;
}
Substring of Sorted String 题解的更多相关文章
- F - Substring of Sorted String
题目链接 题解(树状数组) 我们维护两个树状数组,一个记录 \(1\sim i\) 中 \(s_i>s_{i+1}\)的数量,即逆序对数量,另一个记录 \(1\sim i\) 中 \(26\) ...
- LeetCode 1234. Replace the Substring for Balanced String
原题链接在这里:https://leetcode.com/problems/replace-the-substring-for-balanced-string/ 题目: You are given a ...
- java用substring函数截取string中一段字符串
在String中有两个substring()函数,如下: 一:String.substring(int start) 参数: start:要截取位置的索引 返回: 从start开始到结束的字符串 例如 ...
- [LeetCode]Longest Substring Without Repeating Characters题解
Longest Substring Without Repeating Characters: Given a string, find the length of the longest subst ...
- LeetCode第[5]题(Java):Longest Palindromic Substring 标签:String、动态规划
题目中文:求最长回文子串 题目难度:Medium 题目内容: Given a string s, find the longest palindromic substring in s. You ma ...
- 【leetcode】1234. Replace the Substring for Balanced String
题目如下: You are given a string containing only 4 kinds of characters 'Q', 'W', 'E' and 'R'. A string i ...
- LeetCode longest substring without repeating characters 题解 Hash表
题目 Given a string, find the length of the longest substring without repeating characters. Example 1: ...
- [LeetCode] Decode String 题解
题目 题目 s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return " ...
- [LeetCode]Remove Duplicates from Sorted Array题解
Remove Duplicates from Sorted Array: Given a sorted array, remove the duplicates in place such that ...
- Leetcode Find Minimum in Rotated Sorted Array 题解
Leetcode Find Minimum in Rotated Sorted Array 题目大意: 对一个有序数组翻转, 就是随机取前K个数,移动到数组的后面,然后让你找出最小的那个数.注意,K有 ...
随机推荐
- 企业级GitLab搭建
企业级GitLab搭建 一.简介 1.GitLab概述 是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. Rub ...
- 基于FFMPEG+SDL的简单的视频播放器分析
基于FFMPEG+SDL的简单的视频播放器分析 前言 最近看了雷霄骅前辈的博客<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>,参照他的代码,在window ...
- UE5打包SDK未正确安装的问题
正文 Windows(笔者之前用的电脑是windows10,最新电脑使用的是windows11)下UE5打包项目的需要安装Visual Studio. 而且安装的时候需要选择上C++ 游戏开发相关模块 ...
- kaggle中训练得到的output太大该怎么下载?
最近在使用Kaggle平台训练自己的模型,但是训练结束之后由于模型过大导致output那里一直在加载(转圈),即使加载出来点击download也没有反应 下面借鉴知乎大佬的方法可以完美解决!通过将其压 ...
- github上传文件报错failed to push some refs解决
报错内容,不能推送文件到github上 error: failed to push some refs to github地址 原因是github项目与本地文件夹一些关键文件的确实,比如.git,re ...
- 用Python操控斑马打印机的技术总结
前言 由于之前产品打印的标签为人工输入,可能存在信息错误且不适合大批量操作.所以我进行了前期的研究和总结,完成了任务,并这里做下技术总结,方便后面的人进行开发. 技术总结 斑马打印机的坑 官网:htt ...
- SpringBoot项目:net.sf.jsqlparser.parser.ParseException: Encountered unexpected token:XXXXX
原文地址 写在前面 最近开发过程中,在where条件中使用IF函数,在MySQL数据库中,使用Navicat运行没有问题,但是运行项目的时候,死活过不去,一直报错,后来一番折腾找到了解决方案,所以,以 ...
- 在windows平台使用Visual Studio 2017编译动态库并使用
使用VS stdio制作顺序表的库文件 .lib与.dll 区别 lib是编译时需要的 dll是运行时需要的 1.新建头文件和源文件 SeqList.h // SeqList.h #ifndef SE ...
- 【技术积累】Linux中的命令行【理论篇】【二】
ag命令 命令介绍 ag命令是一个用于在Linux系统中进行文本搜索的工具.它是基于Silver Searcher的改进版本,具有更快的搜索速度和更强大的功能. ag命令的基本用法是在指定的目录中搜索 ...
- Promise的理解与使用(一)
一.Promise是什么?Promise是JS中进行异步操作的新的解决方案(旧的方案是回调函数的形式,回调函数里嵌套函数)从语法上来说,Promise是一个构造函数.从功能上来说,用Promise的实 ...