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

线段树查询区间回文+区间字母右移

线段树查询区间回文 + 区间字母右移

属于一道很有意思的线段树,线段树维护以下信息。

struct node{int l, r, ln;int hash1[26], hash2[26];int tag;
}tr[N << 2];

维护线段左右端点,线段长度, 26 26 26 个字母的哈希值,以及区间移动懒标记。

关于 h a s h 1 hash1 hash1 ,表示一个区间的正哈希值,例如 a b c d a abcda abcda h a s h 0 = p 0 + p 4 hash_0=p^0+p^4 hash0=p0+p4 , h a s h 1 = p 1 hash_1=p^1 hash1=p1 , h a s h 2 = p 2 hash_2=p^2 hash2=p2 , h a s h 3 = p 3 hash_3=p^3 hash3=p3

也就是说, h a s h i hash_i hashi 维护对应字母在当前线段自己位置的哈希值。

那么显然 ∑ i = 0 26 h a s h i × i \sum_{i=0}^{26}hash_i\times i i=026hashi×i 就是一条线段的哈希值。

只需要维护正反两种哈希即可 。

剩下就是上传和下传操作了,对于上传,想要拼接 p 0 + p 1 + p 3 p_0+p_1+p_3 p0+p1+p3 p 0 + p 1 p_0+p_1 p0+p1 ,显然右边应该再乘上 p l . l n p^{l.ln} pl.ln

对于下传,其实本质就是交换哈希值,开两个临时数组备份一下 h a s h 1 hash1 hash1 h a s h 2 hash2 hash2 ,然后移动一下哈希值即可。

#include<bits/stdc++.h>
using namespace std;
#define int long longstring s;int const N = 1e5 + 10;#define lc u << 1
#define rc u << 1 | 1int const P = 13331;
int const mod = 1e9 + 7;int p[N];struct node{int l, r, ln;int hash1[26], hash2[26];int tag;
}tr[N << 2];void pushup(node &u, node &lson, node &rson){u.l = lson.l, u.r = rson.r, u.ln = lson.ln + rson.ln;for(int i = 0; i < 26; i ++){ u.hash1[i] = (lson.hash1[i] + rson.hash1[i] * p[lson.ln] % mod) % mod;u.hash2[i] = (rson.hash2[i] + lson.hash2[i] * p[rson.ln] % mod) % mod;}
}void pushup(int u){pushup(tr[u], tr[lc], tr[rc]);
}void build(int u, int l, int r){tr[u].l = l, tr[u].r = r, tr[u].ln = 1, tr[u].tag = 0;memset(tr[u].hash1, 0, sizeof tr[u].hash1);memset(tr[u].hash2, 0, sizeof tr[u].hash2);tr[u].hash1[s[l] - 'a'] = tr[u].hash2[s[l] - 'a'] = p[0]; // can delete laterif(l == r) return ; int mid = l + r >> 1;build(lc, l, mid), build(rc, mid + 1, r);pushup(u);
}  void pushdown(int u, int tag){tag %= 26;if(tag){vector<int> t1(26, 0), t2(26, 0);for(int i = 0; i < 26; i ++){t1[i] = tr[u].hash1[i];t2[i] = tr[u].hash2[i];}for(int i = 0; i < 26; i ++){ int las = (i + tag) % 26;tr[u].hash1[las] = t1[i];tr[u].hash2[las] = t2[i];}tr[u].tag = (tr[u].tag + tag) % 26;}
}void pushdown(int u){pushdown(lc, tr[u].tag);pushdown(rc, tr[u].tag);tr[u].tag = 0;
}void segMove(int u, int l, int r, int v){if(l <= tr[u].l && r >= tr[u].r){pushdown(u, v);return ;}int mid = tr[u].l + tr[u].r >> 1;pushdown(u);if(l <= mid) segMove(lc, l, r, v);if(r > mid) segMove(rc, l, r, v);pushup(u);
}node askHash(int u, int l, int r){if(l <= tr[u].l && r >= tr[u].r){return tr[u];}int mid = tr[u].l + tr[u].r >> 1;pushdown(u);if(r <= mid) return askHash(lc, l, r);else if(l > mid) return askHash(rc, l, r);else{node res, lres = askHash(lc, l, r), rres = askHash(rc, l, r);pushup(res, lres, rres);return res;}
}void solve(){int n, m;cin >> n >> m >> s;s = ' ' + s;build(1, 1, n);  while(m --){int op, l, r, v;cin >> op >> l >> r;if(op == 1){node res = askHash(1, l, r);int hash1 = 0, hash2 = 0;for(int i = 0; i < 26; i ++){hash1 = (hash1 + i * res.hash1[i] % mod) % mod;hash2 = (hash2 + i * res.hash2[i] % mod) % mod;} cout << (hash1 == hash2 ? "YES" : "NO") << '\n';}else{cin >> v;segMove(1, l, r, v);}}
}signed main(){ios::sync_with_stdio(false);cin.tie(0), cout.tie(0); p[0] = 1;for(int i = 1; i < N; i ++){p[i] = p[i - 1] * P % mod;}int T = 1;while (T --){solve();}return 0;
}

相关文章:

  • Python NumPy 标准数据生成:高效创建与操作数组
  • SQL Server实现limit用法
  • 初识chatgpt
  • cnn机器学习时python版本不兼容报错
  • Android 10.0 Launcher3禁止改变density等系统密度导致布局变化hotseat靠右边显示功能实现
  • 查询最近正在执行的sql(DM8 : 达梦数据库)
  • Electron 隐藏顶部菜单
  • Docker的安装和使用
  • 一文详解大语言模型Transformer结构
  • LangGPT结构化提示词编写实践
  • 金融教育宣传月 | 平安养老险百色中心支公司开展金融知识“消保县域行”宣传活动
  • 如何使用ssm实现个人日常事务管理系统+vue
  • 【数据结构与算法 | 灵神题单 | 栈基础篇】力扣155, 1472, 1381
  • Python 将数据写入 excel(新手入门)
  • mac Wireshark You do not have permission to capture on device “rvio“.
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • “大数据应用场景”之隔壁老王(连载四)
  • Java|序列化异常StreamCorruptedException的解决方法
  • Javascript基础之Array数组API
  • LeetCode29.两数相除 JavaScript
  • mac修复ab及siege安装
  • PHP 7 修改了什么呢 -- 2
  • php中curl和soap方式请求服务超时问题
  • socket.io+express实现聊天室的思考(三)
  • 大快搜索数据爬虫技术实例安装教学篇
  • 对JS继承的一点思考
  • 番外篇1:在Windows环境下安装JDK
  • ------- 计算机网络基础
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 聊聊redis的数据结构的应用
  • 深度学习入门:10门免费线上课程推荐
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 微信小程序--------语音识别(前端自己也能玩)
  • 新书推荐|Windows黑客编程技术详解
  • #define
  • #nginx配置案例
  • #QT项目实战(天气预报)
  • #stm32驱动外设模块总结w5500模块
  • $.ajax()方法详解
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (c语言+数据结构链表)项目:贪吃蛇
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (SERIES10)DM逻辑备份还原
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (一)模式识别——基于SVM的道路分割实验(附资源)
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)h264中avc和flv数据的解析
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .NET编程——利用C#调用海康机器人工业相机SDK实现回调取图与软触发取图【含免费源码】
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .NET建议使用的大小写命名原则