2020牛客国庆集训派对day8 G-Shuffle Cards(扩展STL容器,rope可持久化平衡树)
题目
https://ac.nowcoder.com/acm/contest/7865/G
题意
给你n张牌,要你洗k次牌。
后面k行数据,p,s表示将第p张牌后的s张牌,放到牌顶。
让你求k次操作之后牌的顺序。
题解
这就很明显是个区间插入、删除的操作模拟,可是因为n,k都是1e5的,所以正常用vector写肯定TLE。在这里就需要用到神奇的东西——rope容器。
rope是什么?
rope 不属于标准 STL,属于扩展 STL,来自 pb_ds 库 (Policy-Based Data Structures)
它的头文件:#include<ext/rope> (注:可以打开devcpp的目录去rope这个头文件看看它的操作)
它的名称空间:using namespace __gnu_cxx;
定义方法:rope<变量类型>变量名称;
或 crope 变量名称;
其中crope相当于定义成rope < char >,即定义为string类型
rope 解释
算法解释:块状链表(即讲链表与数组的优势结合,形成分块思想)
用途解释:这本来是一个用于快速操作string的工具,却一般被定义成int,然后用作可持久化线段树!
rope 内部是块状链表实现的,黑科技是支持 O(1) 复制,而且不会空间爆炸 (rope 是平衡树,拷贝时只拷贝根节点就行)。因此可以用来做可持久化数组。
经典的可持久化线段树的图解
支持的操作:
#include <ext/rope> // 头文件
using namespace __gnu_cxx; // 注意名称空间
rope<int> rp;
int main() {
rp.push_back(x); // 在末尾插入 x
rp.insert(pos, x); // 在 pos 处插入 x
rp.erase(pos, x); // 在 pos 处删除 x 个元素
rp.length(); // 返回 rp 的大小
rp.size(); // 同上
rp.replace(pos, x); // 将 pos 处的元素替换成 x
rp.substr(pos, x); // 从 pos 处开始提取 x 个元素
rp.copy(pos, x, s); // 从 pos 处开始复制 x 个元素到 s 中
rp[x]; // 访问第 x 个元素
rp.at(x); // 同上
return 0;
}
AC 代码
#include <bits/extc++.h>
#include <bits/stdc++.h>
using namespace std;
using namespace __gnu_cxx;
const int N = 100010;
int main() {
int n, m, a[N] = {0}; cin >> n >> m;
for (int i = 0; i < n; i++) a[i] = i + 1;
rope<int> rp(a);
while (m--) {
int p, s; cin >> p >> s; p--;
rp.insert(0, rp.substr(p, s));
rp.erase(p + s, s);
}
for (auto i : rp) cout << i << " ";
return 0;
}