*【学习笔记】(10) 块状链表
块状链表(尚未完善)
对于线性表,可以
对于链表,可以
于是本着分块的思想,有了块状链表 。
大概长这个样子。每个块的大小数量级在
注:图片来自 https://www.cnblogs.com/spaceswalker/p/16553849.html
主要有以下几种操作:
插入
1.分裂节点
2.在分裂点插入
删除
1.删除开头节点的后半部分
2.删除中心完整节点
3.删除结尾节点的前半部分
合并
为了保证正确的复杂度,要不定期的进行合并操作。
所谓合并操作,就是从第一个块开始,如果把下一个块合并过来之后大小不大于
若没有合并操作,则可能会有很多小块,导致 TLE
P4008 [NOI2003] 文本编辑器
暂时不想打,有时间的话会补回来的
可持久化杀手——rope
#include<ext/rope> // 头文件 using namespace __gnu_cxx; //引用 rope rope<char> a; //建立一个存储 char 的 rope // rope<变量类型> 变量名称; crope a; //实际就是 rope<char> a // 下标从 0 开始 a.push_back(x) //在末尾添加 x a.insert(pos, x) //在 pos 插入 x a.erase(pos, x) //从 pos 开始删除 x个 a.replace(pos, x) //从 pos 开始换成 x a.substr(pos, x) //提取 pos开始 x个 a.at(x) / a[x] //访问第 x个元素 a.length() / a.size() //返回 a 的大小 a.copy(pos, x, s) //将从 pos位置开始 x个元素提取到 s中 O(1) a.append(string &s / int *a, int 串s的起始位置, int 长度) //插入 s的 pos开始的 n位 (暂时还不知道怎么用) //如果需要翻转平衡树,就维护一正一反两个rope,翻转就把两个rope交换一下就行了。
P4008 [NOI2003] 文本编辑器
用上述的操作就可以实现了
#include<bits/stdc++.h> #include<ext/rope> using namespace std; using namespace __gnu_cxx; inline int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } crope a; int m, pos; inline void in(int x){ int pos1 = pos; while(x){ char ch = getchar(); if((int)ch >= 32 && (int)ch <= 126) a.insert(pos1, ch), --x, pos1++; } return ; } int main(){ m = read(); while(m--){ char opt[51]; scanf("%s", opt + 1); if(opt[1] == 'M') pos = read(); else if(opt[1] == 'I') in(read()); else if(opt[1] == 'D') a.erase(pos, read()); else if(opt[1] == 'G') cout << a.substr(pos, read()) << endl; else if(opt[1] == 'P') --pos; else if(opt[1] == 'N') ++pos; } return 0; }
P4567 [AHOI2006]文本编辑器
较上题多了反转操作,我们可以维护两个 rope ,一个正序,一个逆序
#include<bits/stdc++.h> #include<ext/rope> using namespace std; using namespace __gnu_cxx; const int N = 1 << 22; inline int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } rope<char> a, b, t; int m, pos; char a1[N], a2[N]; inline void in(int x){ int pos1 = pos; for(int i = 0; i < x; ++i) a1[i] = a2[x - i - 1] = getchar(); a1[x] = '\0', a2[x] = '\0'; int len = a.size(); a.insert(pos, a1), b.insert(len - pos, a2); return ; } inline void del(int x){ int len = a.size(); a.erase(pos, x), b.erase(len - pos - x, x); } inline void rotate(int x){ int len = a.size(); t = a.substr(pos, x); a = a.substr(0, pos) + b.substr(len - pos - x, x) + a.substr(pos + x, len - pos - x); b = b.substr(0, len - pos - x) + t + b.substr(len - pos, pos); } inline void out(){ putchar(a[pos]); if(a[pos] != '\n') putchar('\n'); } int main(){ cin.tie(0), cout.tie(0); m = read(); while(m--){ char opt[51]; scanf("%s", opt + 1); if(opt[1] == 'M') pos = read(); else if(opt[1] == 'I') in(read()); else if(opt[1] == 'D') del(read()); else if(opt[1] == 'G') out(); else if(opt[1] == 'P') --pos; else if(opt[1] == 'N') ++pos; else if(opt[1] == 'R') rotate(read()); } return 0; }
P3850 [TJOI2007]书架
按题意操作即可
#include<bits/stdc++.h> #include<ext/rope> using namespace std; using namespace __gnu_cxx; const int N = 2e5 + 51; inline int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } int n, m, q; rope<int> a; string s[N]; int main(){ cin.tie(0), cout.tie(0); n = read(); for(int i = 1; i <= n; ++i) cin >> s[i], a.push_back(i); m = read(); for(int i = 1; i <= m; ++i) cin >> s[i + m], a.insert(read(), i + m); q = read(); while(q--) cout << s[a.at(read())] << endl; return 0; }
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17417628.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步