COGS2421 [HZOI 2016]简单的Treap

 

题面见这里

大概是个模板题

Treap暴力插入的做法太暴力了并不优美

这里就需要用到笛卡尔树的构造方法,定义见这里

在 假的O(n) 的时间内构造一棵Treap

把元素从小到大排序

这样从小到大插入时,只会往树上最右边的链上走

这样考虑一下 Treap 正常的 Insert 的过程:

  只要找到第一个优先级更小(大根堆)的节点,将待插入节点插到上一层的右儿子的位置

  将当前找到的节点作为待插入节点的左儿子

这样就类似一个旋转操作,也就成功的模拟实现出了一个的 Treap 完整的 Insert 的过程

 

具体在代码里是这样的:

  用一个单调栈维护整个树的最右边的链

  边找符合要求的节点边出栈

  找到之后进行上面提到的操作即可

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<stack>
using namespace std;

const int MAXN = 500001;

struct Node{
	int ch[2], val, prio;
	Node(){ch[0] = ch[1] = val = 0;}
	bool operator < (const Node &b) const{
		return val < b.val;
	}
}t[MAXN];
int n, top, stk[MAXN];

inline int rd() {
	register int x = 0;
	register char c = getchar();
	register bool f = false;
	while(!isdigit(c)) {
		if(c == '-') f = true;
		c = getchar();
	}
	while(isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}
stack<int> dfs;
bool vis[MAXN];
void Recycle() {
	dfs.push(stk[1]);
	vis[0] = true;
	while(dfs.size()) {
		int cur = dfs.top();
		if(!vis[cur]) {
			vis[cur] = true;
			printf("%d ", t[cur].val);
		}
		if(!vis[t[cur].ch[0]]) dfs.push(t[cur].ch[0]);
		else if(!vis[t[cur].ch[1]]) dfs.push(t[cur].ch[1]);
		else dfs.pop();
	}
	return;
}

int main() {
	freopen("treap.in", "r", stdin);
	freopen("treap.out", "w", stdout);
	n = rd();
	for(int i = 1; i <= n; ++i) t[i].val = rd();
	for(int i = 1; i <= n; ++i) t[i].prio = rd();
	sort(t + 1, t + n + 1);
	stk[++top] = 1;
	for(int i = 2; i <= n; ++i) {
		int last = 0;
		while(top and t[stk[top]].prio > t[i].prio) last = stk[top--];
		t[i].ch[0] = last;
		if(top) t[stk[top]].ch[1] = i;
		stk[++top] = i;
	}
	//printf("root %d\n", stk[1]);
	Recycle();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

  


 

posted @ 2018-05-23 19:58  EvalonXing  阅读(330)  评论(0编辑  收藏  举报