题目大意:构造一棵笛卡尔树。
这题一拿到手就想着用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;
}