题目大意:给定一个数组1 2 3 4 5…
有m次操作,每次给定一个p和s,然后将数组中[p,p+s-1]中的数放到数组最前方。最后输出操作完后的顺序
实际上这个操作转化成可以分成三次翻转
假设p=2,s=3,
1:翻转[1,p+s-1]
4 3 2 1 5
2:翻转[1,3]
2 3 4 1 5
3 翻转[4,4]
2 3 4 1 5
形式化来讲就是
int l = 1, r = p + s - 1;
rev(l, r); //
rev(l, s);
rev(s + 1, r);
显然,这是经典的splay翻转板子,抄一份模板即可
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e6 + 10;
struct node {
int s[2], fa, id, siz;
int flag;
void init(int _id, int _fa) {
id = _id;
fa = _fa;
}
} tr[N];
int n, m, idx, root;
void push_up(int u) {
tr[u].siz = tr[tr[u].s[0]].siz + tr[tr[u].s[1]].siz + 1;
}
void push_down(int u) {
swap(tr[u].s[0], tr[u].s[1]);
tr[tr[u].s[0]].flag ^= 1;
tr[tr[u].s[1]].flag ^= 1;
tr[u].flag = 0;
}
//把x点旋转到k点
void rotate(int x) {
int y = tr[x].fa, z = tr[y].fa;//找到父亲与祖父
int k = tr[y].s[1] == x; //判断x是否为父亲的右儿子
tr[z].s[tr[z].s[1] == y] = x, tr[x].fa = z;
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].fa = y;
tr[x].s[k ^ 1] = y;
tr[y].fa = x;//反正就是把x转上去一位,不需要记过程
push_up(y);
push_up(x);
}
void splay(int x, int k) {
while (tr[x].fa != k) {
int y = tr[x].fa, z = tr[y].fa; //分别是y父亲与z祖父
if (z != k) {
if ((tr[y].s[1] == x) != (tr[z].s[1] == y))
rotate(x);//把x往上旋转一位
//是父亲的右儿子是x,且祖父的右儿子是y(要求两者一左一右才能转x)
//如果都是左左或者右右
else
rotate(y);//把y往上旋转一位
}
rotate(x);//再旋转一位x
}
if (!k)
root = x;
}
void insert(int v) {
int u = root, p = 0;
while (u) {
p = u;
u = tr[u].s[v > tr[u].id]; //如果插入值比当前节点大就插入到右儿子
}
u = ++idx; //分配节点编号
if (p)
tr[p].s[v > tr[u].id] = u;
tr[u].init(v, p);
splay(u, 0); //把u节点转到0点上
}
int get(int u, int k) {
if (tr[u].flag)
push_down(u);
int cnt = tr[tr[u].s[0]].siz;
if (cnt >= k)
return get(tr[u].s[0], k);
else if (cnt + 1 == k)
return u;
else {
k -= cnt + 1;
return get(tr[u].s[1], k);
}
return -1;
}
void rev(int l, int r) {
l = get(root, l), r = get(root, r + 2);
splay(l, 0); splay(r, l);//把两个区间转上去,此时l,r之间的区域就出现在了r的左儿子的位置上
tr[tr[r].s[0]].flag ^= 1; //把l到r区间打上旋转标记
}
void print(int u) {
if (tr[u].flag)
push_down(u);//遇到标记先处理
if (tr[u].s[0])
print(tr[u].s[0]);
if (1 <= tr[u].id && tr[u].id <= n)
cout << tr[u].id << " ";
if (tr[u].s[1])
print(tr[u].s[1]);
}
void solve() {
cin >> n >> m;
for (int i = 0; i <= n + 1; i++) {
insert(i);
}
while (m--) {
int p, s;
cin >> p >> s;
int l = 1, r = p + s - 1; //r是取出时的右端
rev(l, r); //
rev(l, s);
rev(s + 1, r);
}
print(root);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}