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. Transaction rolled back because it has been marked as rollback-only大概问题及解决方法

    Transaction rolled back because it has been marked as rollback-only 问题:前几天遇到一个问题,代码没有抛出我想要的带自定义提示消息的 ...

  2. RabbitMQ升级过程以及问题解决

    1.卸载MQ 如果安装过MQ需先彻底卸载ERlangOTP与rabbitMQ,卸载步骤如下 1.  停止RabbitMQ服务 2.  在控制面板中卸载Erlang与RabbitMQ 3.  删除C:\ ...

  3. Java扩展Nginx之四:远程调试

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<Java扩展Nginx> ...

  4. Cilium系列-5-Cilium替换KubeProxy

    系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, ...

  5. Java并发篇:6个必备的Java并发面试种子题目

    线程创建和生命周期 线程的创建和生命周期涉及到线程的产生.执行和结束过程.让我们继续深入探索这个主题: 线程的创建方式有多种,你可以选择适合你场景的方式: 继承Thread类: 创建一个类,继承自Th ...

  6. wget: 未找到命令

    输入以下命令: yum -y install wget

  7. loader的三种配置方式

    在这篇 webpack处理css资源 文章中使用几个常用的loader 来编译 css 代码. 但其实 loader 的配置方式不止一种,一起来看看其它方式~ 在 webpack.config.js ...

  8. [nginx]借助nginx实现自动获取本机IP

    前言 在用脚本自动化部署应用时,有的应用需要指定本机IP,网上找到的方案大多是过滤ifconfig或者ip命令的结果,这里提供一种通过nginx获取本机ip的方法.大致思路为客户端向nginx发起请求 ...

  9. RocketMQ 系列(二) 环境搭建

    RocketMQ 系列(二) 环境搭建 上一个章节对于 RocketMQ 作了一些概念上的介绍,如果你对于 RocketMQ 没有概念,不妨先看RocketMQ系列(一) 基本介绍. 这个章节主要介绍 ...

  10. 快手商品详情API接口如何使用

    使用快手开的API接口获取商品详情,可按照以下步骤进行: 1.注册账号并创建应用 注册开发者账号,并在账号后台中创建一个应用,获得AppKey和AppSecret等信息.这些信息是使用API接口访问快 ...