隐藏页面特效

FHQ_treap究极完全板子

1|0究极FHQ_treap非指针版板子



例题

1|1匹配


题目描述

给定一个仅含小写字母的字符串 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解题思路


操作1 2 就是基本的加点和删点
操作3 参考洛谷P3391文艺平衡树区间翻转板题
对于操作4,给每个节点对应的序列维护hash来比较
值得注意的是
打上lazy以后一定要处理这个节点的值
因为在update操作中
单独只处理当前根的hash值是不够的,会调用到子节点的hash值


1|3code:


#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); //LUCKY NUMBER!! ull pw[N], pw2[N], base = 2333, base2 = 20051207; //const ull md1 = 1e18 + 7, md2 = 1e18 + 9; 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 ; } /* 非常重要的批注: 打上lazy以后一定要处理这个节点的值 因为在update操作中 单独只处理当前根的hash值是不够的,会调用到子节点的值 总而言之标记不是指这个点需要处理(所以打上标记的时候就要把相关的值都算好) 而是指这个点的子节点需要处理 */ 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] ); // % md1; hs[rt][1] = ( hs[l][1] + val[rt] * pw[siz[l]] + hs[r][1] * pw[siz[l] + 1] ); // % md1; hs2[rt][0] = ( hs2[l][0] * pw2[siz[r] + 1] + val[rt] * pw2[siz[r]] + hs2[r][0] ); // % md2; hs2[rt][1] = ( hs2[l][1] + val[rt] * pw2[siz[l]] + hs2[r][1] * pw2[siz[l] + 1] ); // % md2; } 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) {//按中序分成左边k个点, 剩下的在右边 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) {//删去中序的第k个 int x, y, z; split_siz(rt, k - 1, x, y); split_siz(y, 1, y, z); //y = merge(ls[y], rs[y]); rt = merge(x, z); } void print_mid(int rt) { if (!rt) return ; push_down(rt); print_mid(ls[rt]); // printf("%c", char(val[rt] + 'a')); 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); // print_mid(y); //cout<<endl; 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); // print_mid(y); //cout<<endl; 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 /*&& tag02 == tag12*/ && tag03 == tag13 /*&& tag04 == tag14*/; } }T; void init() { pw[0] = pw2[0] = 1; for (int i = 1; i <= N - 2; i++) { pw[i] = pw[i - 1] * base; // % md1; pw2[i] = pw2[i - 1] * base2; // % md2; } } int n, m; char s[N]; signed main() { // freopen("match.in", "r", stdin); // freopen("match.out", "w", stdout); 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'); } // T.print_mid(rt); cout<<endl; 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("ans = %d\n", ans); } // T.print_mid(rt); //cout<<endl; } printf("%d", ans); } /* */

还有string暴力版
(谨记我痛苦的对拍时光)

#include<bits/stdc++.h> #define reg register int using namespace std; const int N = 2e5 + 5; int n, m, ans; string s; inline bool cmp(int p, int q, int len) { for(reg i = 0; i < len; i++) if(s[p + i] != s[q + i]) return false; return true; } int main() { // freopen("match.in","r",stdin); // freopen("match.out","w",stdout); int opt, p, q, len; char c; scanf("%d %d", &n, &m); cin>>s; while(m--) { scanf("%d", &opt); switch(opt) { case 1: { scanf("%d %c\n", &p, &c); s.insert(p, 1, c); break; } case 2: { scanf("%d", &p); s.erase(p, 1); break; } case 3: { scanf("%d %d", &p, &q); reverse(s.begin() + p,s.begin() + q + 1); break; } case 4: { scanf("%d %d %d", &p, &q, &len); if(cmp(p,q,len)) ans++; break; } } } printf("%d\n", ans); return 0; }

__EOF__

本文作者Aiza's Blog
本文链接https://www.cnblogs.com/Aiza/p/16295568.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Aiza  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示