sgu 155 - 笛卡尔树

本文介绍了一种使用Treap方法构建笛卡尔树的有效算法。通过先排序节点再按特定策略插入,避免了树形结构的退化,确保了O(nlogn)的时间复杂度。文章详细解释了插入和调整过程。

题目大意:构造一棵笛卡尔树。

这题一拿到手就想着用treap的方法做了。但是在test15的地方TLE了很多次,上网看了别人的题解,才知道问题出在哪里。

确实用treap的方法做就可以了,问题是,每次插入的时候,如果整棵树退化成一个单链,插入需要的时候会退化为O(n^2),为了解决这个问题,需要先把结点按照k递增排序,然后依次插入。可是,这样做岂不是一定会退化成单链?!是的,所以,我们在插入的时候,并不需要从根结点开始查找恰当的插入位置,我们可以用一个farRight来记住整棵树的最小元素的位置,每次插入直接插到farRight的右儿子。这样,我们就可以让所有结点的插入时间控制为O(n)。然后,关于旋转时间的分析,显然,我们只会用到右旋转,而且每次旋转都会把某个结点旋到左边,而且,一旦某个父亲节点被旋到了左边,它就再也回不来了,所以,由于每个结点只会被旋转到左边一次,所以旋转的总时间也是O(n)。

加上排序的时间,最后整个算法的时间是O(nlogn)

#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;

struct Node {
    Node* L;
    Node* R;
    Node* father;
    int id;
    int k, a;
};

typedef Node* NodePointer;

struct __cmpByK {
    bool operator() (const NodePointer &a, const NodePointer &b) const {
        return a->k < b->k;
    }
} cmpByK;


// 全局变量 ========================================

Node* NullNode;

int N;
Node* gRoot;

vector< Node* > nodes;
vector< Node* > dealList;

int freeId = 0;
Node __cache[50000 + 5];

Node* farRight;
//===================================================

Node* newNode() {
    return &(__cache[freeId++]);
}


Node* insertNode(Node* x) {
    // if (root == NullNode) {
        // x->L = x->R = NullNode;
        // return x;
    // }

    // if (x->k < root->k) {
        // root->L = insertNode(root->L, x);
        // root->L->father = root;
    // }
    // else if (x->k > root->k) {
        // root->R = insertNode(root->R, x);
        // root->R->father = root;
    // }
    // return root;

    farRight->R = x;
    x->L = x->R = NullNode;
    x->father = farRight;
    farRight = x;
}


bool floatUp(Node* x) {
    if (x->father == NullNode) return false;
    if (x->father->a < x->a) return false;

    //如果我是左子树
    // if (x->father->L == x) {
        // Node* A = x->L, *B = x->R;
        // Node* y = x->father;


        //将B交给y
        // y->L = B;
        // B->father = y;

        //将x的father变为y的father
        // x->father = y->father;
        // if (y->father->L == y) { y->father->L = x; }
        // else { y->father->R = x; }

        // y->father = x;
        // x->R = y;
    // }
    //否则,我是右子树
    // else {
    Node* A = x->L, *B = x->R;
    Node* y = x->father;

    y->R = A;
    A->father = y;

    x->father = y->father;
    if (y->father->L == y) { y->father->L = x; }
    else { y->father->R = x; }

    y->father = x;
    x->L = y;
    // }

    return true;

}



void output() {
    NullNode->id = 0;
    printf("YES\n");
    for (int i = 1; i <= N; ++i) {
        printf("%d %d %d\n", nodes[i]->father->id, nodes[i]->L->id, nodes[i]->R->id);
    }
}


void dealWith(Node* cur) {
    insertNode(cur);
    // gRoot->father = NullNode;


    while (floatUp(cur)); // 故意这样写的
    if (cur->father == NullNode) gRoot = cur; //别漏了这个!
}

void run() {
    int i;
    NullNode = newNode();
    scanf("%d", &N);
    nodes.resize(N  + 1);
    dealList.resize(N + 1);
    gRoot = NullNode;

    for (i = 1; i <= N; ++i) {
        Node* cur = newNode();
        scanf("%d %d", &(cur->k), &(cur->a));
        cur->id = i;
        nodes[i] = cur;
        dealList[i] = cur;

    }


    sort(dealList.begin() + 1, dealList.begin() + N + 1, cmpByK);


    for (i = 1; i <= N; i += 1) {
        if (i == 1) {
            gRoot = dealList[1];
            gRoot->L = NullNode;
            gRoot->R = NullNode;
            gRoot->father = NullNode;
            farRight = gRoot;
        } else {
            dealWith(dealList[i]);
        }
    }
    output();
}

int main() {
    run();
    return 0;
}

转载于:https://my.oschina.net/mustang/blog/57155

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值