例题
题目描述
给定一个仅含小写字母的字符串 S[0..n-1],对于一个询问 (p, q, len),我们想知道它的两个子串 S[p..p+len-1]、S[q..q+len-1] 是否相同。更多地,我们希望在对串 S 完成一些操作之后还能高效地得到这个结果。 我们具体要维护以下几个操作(其中 L 为操作之前的串长):
● 1 p c:在下标 p 之前插入一个小写字母 c,0<=p<=L,p=0 意味在头插入,p=L意味在尾插入;
● 2 p: 删除 S[p],其中 0<=p < L;
● 3 p q: 将 S[p..q] 翻转为 S[q..p],例如 batta 经过 “3 1 3” 之后为 bttaa;
● 4 p q len: 表示一次询问操作,询问 S[p..p+len-1] 与 S[q..q+len-1] 是否相同,其中 0<=p<=p+len-1
输入格式
第 1 行为两个整数 n, m,分别表示字符串的初始长度和操作次数;
第 2 行为一个长度为 n 的字符串;
接下来 m 行,每行为一个操作。
输出格式
仅一行一个整数,表示询问相同的次数。
样例输入
4 4
aacb
2 2 // aab
1 2 b // aabb
3 1 2 // abab
4 0 2 2 // ab == ab
样例输出
1
数据范围与约定
对于前 20%的数据满足 n,m≤1000;
对于前 70%的数据满足仅含有 3、4 两种操作;
对于 100%的数据满足 1≤n, m≤200000。
操作1 2 就是基本的加点和删点
操作3 参考洛谷P3391文艺平衡树区间翻转板题
对于操作4,给每个节点对应的序列维护hash来比较
值得注意的是
打上lazy以后一定要处理这个节点的值
因为在update操作中
单独只处理当前根的hash值是不够的,会调用到子节点的hash值
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
inline int read() {
char ch = getchar();
int res = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
res = (res << 1) + (res << 3) + (ch ^ 48);
ch = getchar();
}
return res;
}
const int N = 400005;
mt19937 rd(20051207);
ull pw[N], pw2[N], base = 2333, base2 = 20051207;
struct FHQ_treap {
int ls[N], rs[N], siz[N], rank[N];
int val[N], lazy[N];
int cnt;
ull hs[N][2], hs2[N][2];
void add_lazy(int rt) {
if (rt) {
lazy[rt] ^= 1;
swap(ls[rt], rs[rt]);
swap(hs[rt][0], hs[rt][1]);
swap(hs2[rt][0], hs2[rt][1]);
}
}
void push_down(int rt) {
if (lazy[rt]) {
add_lazy(ls[rt]);
add_lazy(rs[rt]);
lazy[rt] = 0;
}
return ;
}
void update(int rt) {
siz[rt] = siz[ls[rt]] + siz[rs[rt]] + 1;
int l = ls[rt], r = rs[rt];
hs[rt][0] = ( hs[l][0] * pw[siz[r] + 1] + val[rt] * pw[siz[r]] + hs[r][0] );
hs[rt][1] = ( hs[l][1] + val[rt] * pw[siz[l]] + hs[r][1] * pw[siz[l] + 1] );
hs2[rt][0] = ( hs2[l][0] * pw2[siz[r] + 1] + val[rt] * pw2[siz[r]] + hs2[r][0] );
hs2[rt][1] = ( hs2[l][1] + val[rt] * pw2[siz[l]] + hs2[r][1] * pw2[siz[l] + 1] );
}
void split_val(int rt, int v, int &l, int &r) {
if (!rt) return l = r = 0, void();
push_down(rt);
if (val[rt] <= v) split_val(rs[l = rt], v, rs[rt], r);
if (val[rt] > v) split_val(ls[r = rt], v, l, ls[rt]);
update(rt);
}
void split_siz(int rt, int k, int &l, int &r) {
if (!rt) return l = r = 0, void();
push_down(rt);
if (siz[ls[rt]] < k)
split_siz(rs[l = rt], k - siz[ls[rt]] - 1, rs[rt], r);
else split_siz(ls[r = rt], k, l, ls[rt]);
update(rt);
}
int merge(int l, int r) {
if (!l || !r) return l | r;
int rt;
if (rank[l] <= rank[r]) push_down(l), rs[rt = l] = merge(rs[l], r);
if (rank[l] > rank[r]) push_down(r), ls[rt = r] = merge(l, ls[r]);
update(rt);
return rt;
}
int newnode(int v = 0) {
++cnt;
ls[cnt] = rs[cnt] = 0;
siz[cnt] = 1;
val[cnt] = v;
hs[cnt][0] = hs[cnt][1] = v;
hs2[cnt][0] = hs2[cnt][1] = v;
rank[cnt] = rd();
return cnt;
}
void insert_val(int &rt, int v) {
int x, y;
split_val(rt, v, x, y);
rt = merge(merge(x, newnode(v)), y);
}
void erase_val(int &rt, int v) {
int x, y, z;
split_val(rt, v - 1, x, y);
split_val(y, v, y, z);
y = merge(ls[y], rs[y]);
rt = merge(merge(x, y), z);
}
void insert_siz(int &rt, int k, int v = 0) {
int x, y;
split_siz(rt, k, x, y);
rt = merge(merge(x, newnode(v)), y);
}
void erase_siz(int &rt, int k) {
int x, y, z;
split_siz(rt, k - 1, x, y);
split_siz(y, 1, y, z);
rt = merge(x, z);
}
void print_mid(int rt) {
if (!rt) return ;
push_down(rt);
print_mid(ls[rt]);
print_mid(rs[rt]);
}
void reverse(int &rt, int l, int r) {
int x, y, z;
split_siz(rt, l - 1, x, y);
split_siz(y, r - l + 1, y, z);
add_lazy(y);
push_down(y);
rt = merge(merge(x, y), z);
return ;
}
bool cmp(int &rt, int l, int r, int len) {
int x, y, z;
split_siz(rt, l - 1, x, y);
split_siz(y, len, y, z);
ull tag01 = hs[y][0], tag02 = hs[y][1], tag03 = hs2[y][0], tag04 = hs2[y][1];
rt = merge(merge(x, y), z);
split_siz(rt, r - 1, x, y);
split_siz(y, len, y, z);
ull tag11 = hs[y][0], tag12 = hs[y][1], tag13 = hs2[y][0], tag14 = hs2[y][1];
rt = merge(merge(x, y), z);
return tag01 == tag11 && tag03 == tag13 ;
}
}T;
void init() {
pw[0] = pw2[0] = 1;
for (int i = 1; i <= N - 2; i++) {
pw[i] = pw[i - 1] * base;
pw2[i] = pw2[i - 1] * base2;
}
}
int n, m;
char s[N];
signed main() {
init();
n = read(); m = read();
scanf("%s", s + 1);
int rt = 0, len = strlen(s + 1);
for (int i = 1; i <= len; i++) {
T.insert_siz(rt, i - 1, s[i] - 'a');
}
int ty, p, q, ans = 0; char ch;
while (m--) {
ty = read(); p = read();
if (ty == 1) {
ch = getchar();
T.insert_siz(rt, p, ch - 'a');
}
else if (ty == 2) T.erase_siz(rt, p + 1);
else if (ty == 3) {
q = read();
T.reverse(rt, p + 1, q + 1);
}
else if (ty == 4) {
q = read(); len = read();
if (T.cmp(rt, p + 1, q + 1, len)) ans++;
}
}
printf("%d", ans);
}
还有string暴力版
(谨记我痛苦的对拍时光)
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】