排序机械臂

FHQ Treap解法

这道题当然用好写的fhq解决啦(其实是不会splay)

一开始, 感觉无法同时权值分裂又排名分裂

所以我按排名分裂, 维护子树最小值, 设计一个类似求第k大的函数, 找出区间最小值的位置

详见代码, 还是很好懂的(除get_rk函数, 其他部分和文艺平衡树一样)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>

using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f = 1;
    for (;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
    if (f) x=-x;
}

const int N = 100050;
int tag[N], siz[N];
int son[N][2], rnd[N];
int val[N], mn[N];

struct node {
    int pos, num;
    bool operator < (const node &i) const {
        if (num != i.num) return num < i.num;
        return pos < i.pos;
    }
}a[N];
int n;

int rt, x, y, z;
int tot;
int build(int x) {
    val[++tot] = x, mn[tot] = x, siz[tot] = 1;
    rnd[tot] = rand(); return tot;
}

int Mn(int x,int y) {return x < y ? x : y;}

void update(int x) {
    siz[x] = siz[son[x][0]] + siz[son[x][1]] + 1;
    mn[x] = val[x]; 
    if (son[x][0]) mn[x] = Mn(mn[son[x][0]], mn[x]);
    if (son[x][1]) mn[x] = Mn(mn[son[x][1]], mn[x]);
}

void spread(int x) {
    if (!tag[x]) return;
    swap(son[x][0], son[x][1]);
    if (son[x][0]) tag[son[x][0]] ^= 1;
    if (son[x][1]) tag[son[x][1]] ^= 1;
    tag[x] = 0;
}

int merge(int x,int y) {
    if (!x || !y) return x | y;
    if (rnd[x] < rnd[y]) {
        spread(x);
        son[x][1] = merge(son[x][1], y);
        update(x); return x;
    }
    spread(y);
    son[y][0] = merge(x, son[y][0]);
    update(y); return y;
}

void split(int now,int k,int &x,int &y) {
    if (!now) {
        x = y = 0; return;
    }
    spread(now);
    if (siz[son[now][0]] < k) {
        x = now;
        split(son[x][1], k - siz[son[x][0]] - 1, son[x][1], y);
    }
    else y = now, split(son[y][0], k, x, son[y][0]);
    update(now);
}

//找出最小值的排名
int get_rk(int x) {
    int k = 1; //初始排名
    while (1) {
        spread(x);
        if (son[x][0] && mn[son[x][0]] == mn[x]) x = son[x][0]; //在左子树
        else if (son[x][1] && mn[son[x][1]] == mn[x]) k += siz[son[x][0]] + 1, x = son[x][1]; 
        //在右子树
        else return k + siz[son[x][0]]; //在当前节点
    }
}

int v[N];
int main() {
    read(n);
    for (int i = 1;i <= n; i++) {
        read(a[i].num); a[i].pos = i;
    }
    sort(a + 1, a + n + 1);
    for (int i = 1;i <= n; i++)
    v[a[i].pos] = i;
    for (int i = 1;i <= n; i++) 
        rt = merge(rt, build(v[i]));
    for (int i = 1;i <= n; i++) {
        int k = get_rk(rt);
        split(rt, k, x, y);
        split(x, k-1, x, z);
        tag[x] ^= 1;
        rt = merge(x, y);
        printf ("%d ", k + i - 1);
    }
    return 0;
}
/*
7
1 8 6 5 3 5 2

*/

猜你喜欢

转载自www.cnblogs.com/Hs-black/p/12004611.html