大致思路:
1. 发现一个很神奇的性质,无论是操作几的翻转,在同一行的始终在同一行,在同一列的始终在同一列。
2. 对于没有操作2的时候,我们只需要分开维护x轴和y轴哪两段区间翻转了即可,翻转用平衡树来写,这里选择的splay平衡树。
3. 对于有操作2的时候我们会发下进行两次操作2是会复原到原本的矩阵长宽,那么只进行一次操作2后续的操作1该如何维护,观察发现仅是行和列发生了交换,换成维护另一个信息即可。
#include <bits/stdc++.h>
const int N = 1e6 + 10;
typedef std::array<int, 3> ay;
int idx, n , m, root, rev, q;
struct node{
int v, p;
int rev, s[2], size;
inline void init(int _v, int _p){// 初始化新建结点
v = _v;
p = _p;
s[0] = s[1] = 0;
size = 1;
}
}tr[N];
inline void pushup(int u){//上传更新信息
tr[u].size = tr[tr[u].s[0]].size + tr[tr[u].s[1]].size + 1;
}
inline void pushdown(int u){//下传更新信息
if(tr[u].rev){
std::swap(tr[u].s[0], tr[u].s[1]);
tr[tr[u].s[0]].rev ^= 1;
tr[tr[u].s[1]].rev ^= 1;
tr[u].rev = 0;
}
}
inline void rotate(int x){//左旋右旋函数
int y = tr[x].p, z = tr[y].p;
int k = tr[y].s[1] == x;//k为0代表是父节点的左节点,k为1代表室父节点的右节点
tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;//更新x的父节点和y的子节点x应在的位置
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;//更新x的另一条边的父节点为y
tr[x].s[k ^ 1] = y, tr[y].p = x;//更新x的子节点y的信息,和y的父节点为为x的信息
pushup(y), pushup(x);
}
inline void splay(int x, int k){//将下标为x的旋转到下标为k的下面
while(tr[x].p != k){
int y = tr[x].p, z = tr[y].p;
if(z != k)
if((tr[z].s[0] == y) ^ (tr[y].s[0] == x)) rotate(x);//如果是折线先旋转x
else rotate(y);//如果是一条直线那么先旋转y
rotate(x);
}
if(!k) root = x;
}
inline void insert(int v){
int u = root, p = 0;
while(u) p = u, u = tr[u].s[v > tr[u].v];//决定v应该去u的左儿子还是右儿子
u = ++ idx;
if(p) tr[p].s[v > tr[p].v] = u;//决定u应该去p的左儿子还是右儿子
tr[u].init(v, p);
splay(u, 0);
}
inline void go(int u, std::vector<int> &now){
pushdown(u);
if(tr[u].s[0]) go(tr[u].s[0], now);
if(tr[u].v >= 1 && tr[u].v <= n) now.push_back(tr[u].v);
if(tr[u].s[1]) go(tr[u].s[1], now);
}
inline void go2(int u, std::vector<int> &now){
pushdown(u);
if(tr[u].s[0]) go2(tr[u].s[0], now);
if(tr[u].v >= 1 && tr[u].v <= m) now.push_back(tr[u].v);
if(tr[u].s[1]) go2(tr[u].s[1], now);
}
/*
k
/ \
tr[u<<1].size
如果左子树个数>=k 则去左子树里看
如果左子树个数=k-1,则u就是中序遍历第k个点
否则去右子树里看,k-=tr[u<<1].size-1
*/
inline int get_k(int k){
int u = root;
while(true){
pushdown(u);
if(tr[tr[u].s[0]].size >= k) u = tr[u].s[0];
else if(tr[tr[u].s[0]].size + 1 == k) return u;
else k -= tr[tr[u].s[0]].size + 1, u = tr[u].s[1];
}
return -1;
}
inline void solve() {
std::cin >> n >> m >> q;
std::vector<std::vector<int>> g(n + 1, std::vector<int>(m + 1, 0));
std::vector<ay> t;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
std::cin >> g[i][j];
root = idx = rev = 0;
for (int i = 0; i <= n + 1; i ++)
insert(i);
std::vector<int> dx, dy;
for (int i = 0; i < q; i ++) {
int op, x, y;
std::cin >> op;
if (op == 1) {
std::cin >> x >> y;
t.push_back({op, x, y});
} else t.push_back({0, 0, 0});
}
dx.push_back(0);
dy.push_back(0);
for (int i = 0; i < q; i ++) {
auto &[op, x, y] = t[i];
if (op) {
if (rev) {
int l = get_k(1), r = get_k(y + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
if (y + 1 <= n) {
l = get_k(y + 1), r = get_k(n + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
}
} else {
int l = get_k(1), r = get_k(x + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
if (x + 1 <= n) {
l = get_k(x + 1), r = get_k(n + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
}
}
} else {
rev ^= 1;
}
}
go(root, dx);
root = idx = rev = 0;
for (int i = 0; i <= m + 1; i ++)
insert(i);
for (int i = 0; i < q; i ++) {
auto &[op, x, y] = t[i];
if (op) {
if (rev) {
int l = get_k(1), r = get_k(x + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
if (x + 1 <= m) {
l = get_k(x + 1), r = get_k(m + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
}
} else {
int l = get_k(1), r = get_k(y + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
if (y + 1 <= m) {
l = get_k(y + 1), r = get_k(m + 2);
splay(l, 0);
splay(r, l);
tr[tr[r].s[0]].rev ^= 1;
}
}
} else {
rev ^= 1;
}
}
go2(root, dy);
if (!rev) {
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++)
std::cout << g[dx[i]][dy[j]] << ' ';
std::cout << '\n';
}
} else {
for (int i = 1; i <= m; i ++) {
for (int j = 1; j <= n; j ++)
std::cout << g[dx[j]][dy[i]] << ' ';
std::cout << '\n';
}
}
}
int main(void) {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int _ = 1;
//std::cin >> _;
while (_ --) solve();
return 0;
}
标签:std,河南大学,int,tr,void,rev,萌新,2023,inline
From: https://www.cnblogs.com/qdhys/p/17631151.html