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 题解的更多相关文章

  1. F - Substring of Sorted String

    题目链接 题解(树状数组) 我们维护两个树状数组,一个记录 \(1\sim i\) 中 \(s_i>s_{i+1}\)的数量,即逆序对数量,另一个记录 \(1\sim i\) 中 \(26\) ...

  2. LeetCode 1234. Replace the Substring for Balanced String

    原题链接在这里:https://leetcode.com/problems/replace-the-substring-for-balanced-string/ 题目: You are given a ...

  3. java用substring函数截取string中一段字符串

    在String中有两个substring()函数,如下: 一:String.substring(int start) 参数: start:要截取位置的索引 返回: 从start开始到结束的字符串 例如 ...

  4. [LeetCode]Longest Substring Without Repeating Characters题解

    Longest Substring Without Repeating Characters: Given a string, find the length of the longest subst ...

  5. LeetCode第[5]题(Java):Longest Palindromic Substring 标签:String、动态规划

    题目中文:求最长回文子串 题目难度:Medium 题目内容: Given a string s, find the longest palindromic substring in s. You ma ...

  6. 【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 ...

  7. LeetCode longest substring without repeating characters 题解 Hash表

    题目 Given a string, find the length of the longest substring without repeating characters. Example 1: ...

  8. [LeetCode] Decode String 题解

    题目 题目 s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return " ...

  9. [LeetCode]Remove Duplicates from Sorted Array题解

    Remove Duplicates from Sorted Array: Given a sorted array, remove the duplicates in place such that ...

  10. Leetcode Find Minimum in Rotated Sorted Array 题解

    Leetcode Find Minimum in Rotated Sorted Array 题目大意: 对一个有序数组翻转, 就是随机取前K个数,移动到数组的后面,然后让你找出最小的那个数.注意,K有 ...

随机推荐

  1. 谷歌语法的基础知识&FOFA

    谷歌语法 谷歌语法基础符号: "xxx":表示完全匹配,即关键字不能分开,顺序也不能变 +:"xxx"+www.baidu.com  搜索xxx与baidu.c ...

  2. 偷师MapStruct

    转自自己的qq空间 2022年10月26日 一个项目看三遍 每遍都有新发现 嘿嘿嘿 我是代码小偷

  3. 【go语言】2.2.1 数组和切片

    数组和切片是 Go 语言中常用的数据结构,它们都可以存储多个同类型的元素. 数组 数组是具有固定长度的数据类型,它的长度在定义时就已经确定,不能随意改变. 你可以使用以下方式定义一个数组: var a ...

  4. VS Code 有哪些好用的插件呢?【持续更新】

    一.画图工具:vscode-drawio   功能:在 VSCode 中画流程图.数据流图等等.        使用方法:     创建一个后缀名为 .drawio 的文件,然后用 VSCode 打开 ...

  5. tcpdump抓指定端口/ip的数据包

    抓指定端口,这里以7070端口为例 tcpdump -i ens192 port 7070 -s 0 -l -A -w /chris/70.pcap ens192是网卡  抓完ctrl c停止 抓指定 ...

  6. vue vue-simple-uploader 前端的简单使用

    前言 因为项目需要上传大文件tif图,考虑使用分片上传. 1.安装 npm install vue-simple-uploader --save 2.main.js中初始化 import upload ...

  7. [oracle]拆分多用户的公共表空间

    前言 开发环境之前多个用户共用一个表空间,后期维护比较麻烦,因此需要将这些用户拆出来,一个用户一个表空间,以后清理这些用户也更方便. 大致思路:假设A.B.C用户共用一个表空间,将A.B.C的用户数据 ...

  8. 基于inotify-tools和rsync实现文件实时同步

    前言 系统:centos 7 inotify-tools版本:3.14(3.22版本测试有问题,所以找的比较旧的一版) 主机IP: 192.168.137.7(服务端,接收同步文件) 192.168. ...

  9. MyBatis-Plus批量插入方法saveBatch

    1. saveBatch能否提高插入的效率? 先说结论,saveBatch()方法也是一条一条的插入,也就是说它会产生多条insert语句,而不是一条insert语句,所以它不是真正的批量插入,更不能 ...

  10. Redhat 8.2 系统语言切换(英文转中文)

    前提条件 确保已连上网,并且配好 yum 源 若未配好 yum 源 可参考我上一篇文章 部分 Linux 换国内源 操作步骤 安装中文语言包 dnf install glibc-langpack-zh ...