LuoGu P3165 排序机械臂【Splay树区间翻转】

题目连接

题目描述:

区间翻转的


题解:

首先为了方便1~n的翻转,在区间左右加两个哨兵下标分别为1和n + 2,值分别为-INF和INF,然后中序建树,根节点为(1 + n + 2) >> 1,由于在区间中找的数是从小到大排列,所以可以对输入数据进行排序,用一个结构体让下标也跟着被排序(每个数的下标也是在Splay树中的下标),然后遍历排序后的数组,每次将该值的下标旋转到根,根左子树的大小即为答案ans,然后找到应该翻转的区间:左边界为区间第 L = i 个值 (i从2开始,i = 1为哨兵),右边界为第R = ans + 1个(ans为根的左子树大小,而翻转的区间包括根节点,所以+1),然后Reverse(L - 1, R + 1),本题还有一点是在Splay时要进行push_down。


AC代码

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 1e5 + 5, M = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    int l, r, sz, fa, rev, v;
}h[N];
int root;
int n, ans[N], cnt;
pair<int, int> Data[N];

void update(int x) {
    h[x].sz = h[h[x].l].sz + h[h[x].r].sz + 1;
}

void push_down(int x) {
    if (h[x].rev) {
        swap(h[x].l, h[x].r);
        h[h[x].l].rev ^= 1;
        h[h[x].r].rev ^= 1;
        h[x].rev = 0;
    }
}

int Build(int l, int r, int fa) {
    if (l > r) return 0;
    int mid = (l + r) >> 1;
    h[mid].fa = fa, h[mid].sz = 1;
    h[mid].l = Build(l, mid - 1, mid);
    h[mid].r = Build(mid + 1, r, mid);
    update(mid);
    return mid;
}

void Zig(int x) {
    int y = h[x].fa, z = h[y].fa;
    if (h[z].l == y) h[z].l = x;
    if (h[z].r == y) h[z].r = x;
    h[x].fa = z, h[y].fa = x;
    h[y].l = h[x].r, h[h[x].r].fa = y, h[x].r = y;
    update(y), update(x);
}

void Zag(int x) {
    int y = h[x].fa, z = h[y].fa;
    if (h[z].l == y) h[z].l = x;
    if (h[z].r == y) h[z].r = x;
    h[x].fa = z, h[y].fa = x;
    h[y].r = h[x].l, h[h[x].l].fa = y, h[x].l = y;
    update(y), update(x);
}

void Splay(int x, int fa) {
    while (h[x].fa != fa) {
        int y = h[x].fa, z = h[y].fa;
        push_down(z), push_down(y), push_down(x);
        if (h[z].l == y && h[y].l == x && z != fa) {
            Zig(y), Zig(x);
        } else if (h[y].l == x) {
            Zig(x);
        } else if (h[z].r == y && h[y].r == x && z != fa) {
            Zag(y), Zag(x);
        } else {
            Zag(x);
        }
    }
    if (!fa) root = x;
}

int Kth(int k) {
    int z = root;
    while (1) {
        push_down(z);
        int cnt = h[h[z].l].sz + 1;
        if (k < cnt) {
            z = h[z].l;
        } else if (k > cnt) {
            k -= cnt;
            z = h[z].r;
        } else {
            return z;
        }
    }
}

// void In(int x) {
//     push_down(x);
//     if (h[x].l) In(h[x].l);
//     cout << x << " ";
//     if (h[x].r) In(h[x].r);
// }

int main() {
    //freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    Data[1].first = -INF, Data[1].second = 1;
    Data[n + 2].first = INF, Data[n + 2].second = n + 2;
    for (int i = 2; i <= n + 1; i++) {
        cin >> Data[i].first;
        Data[i].second = i;
    }
    root = (1 + n + 2) >> 1;
    Build(1, n + 2, 0);
    sort(Data + 1, Data + n + 2 + 1);
    for (int i = 2; i <= n + 1; i++) {
        Splay(Data[i].second, 0);
        int ans = h[h[root].l].sz;
        cout << ans << ' ';
        int l = Kth(i - 1), r = Kth(ans + 2);
        Splay(l, 0), Splay(r, l);
        h[h[r].l].rev ^= 1;
    }
    cout << '\n';
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值