可合并的TREAP

艰难地A了这个题目。。。还是代码能力太弱了。

主要思想:位置可以变换。。但是某个位置对应的内存地址是不会变的,沿着某个节点的父亲往上暴力统计就能知道他现在在什么位置了,注意先pushDown

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <map>
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
using namespace std;

const int N = 100010;
const int inf = 2000000000;

struct Node{
	Node *l, *r, *p;
	int key, aux, size;
	bool lazy;
}node[N];

typedef Node * Tnode;
Tnode root, nill, stack[N];
int tot;
Tnode pos[N];
int n, q, top;
struct Height
{
	int id, h;
	bool operator < (const Height &s1) const{
		if (h != s1.h) return h < s1.h;
		else return id < s1.id;
	}
}arr[N];

inline void PushDown(Tnode &o){
	if (o == nill) return;
	if (o->lazy){
		swap(o->l->l, o->l->r);
		swap(o->r->l, o->r->r);
		o->l->lazy ^= 1;
		o->r->lazy ^= 1;
		o->lazy = false;
	}
}

inline void PushUp(Tnode &o){
	if (o == nill) return;
	o->size = o->l->size + o->r->size + 1;
	o->l->p = o->r->p = o;
}

inline void Split(Tnode o, Tnode &a, Tnode &b, int num){
	//printf("o:%d  a:%d  b:%d\n", o->key, a->key, b->key);
	if (o->size == num) { a = o, b = nill; return; }
	else if (num == 0){ a = nill, b = o; return; }
	else{
		PushDown(o);
		//    printf("o->l:%d\n", o->l - node);
		if (o->l->size >= num){
			b = o;
			Split(o->l, a, b->l, num);
			PushUp(b);
		}
		else{
			a = o;
			Split(o->r, a->r, b, num - 1 - o->l->size);
			PushUp(a);
		}
	}
}

inline void Merge(Tnode &o, Tnode a, Tnode b){
	if (a == nill) { o = b; return; }
	else if (b == nill) { o = a; return; }
	else {
		if (a->aux <= b->aux){
			PushDown(a);
			o = a;
			Merge(o->r, a->r, b);
		}
		else{
			PushDown(b);
			o = b;
			Merge(o->l, a, b->l);
		}
		PushUp(o);
	}
}

inline void Build(){
	tot = 0;
	nill = &node[tot++];
	nill->aux = inf;
	nill->size = nill->key = 0;
	nill->l = nill->r = nill->p = nill;
	nill->lazy = false;
	root = nill;
}

Tnode NewNode(int key){
	Tnode ret = &node[tot++];
	ret->key = key;
	ret->size = 1;
	ret->aux = ((rand() << 15) + rand()) % inf;
	ret->l = ret->r = ret->p = nill;
	ret->lazy = false;
	return ret;
}

inline void Find(Tnode now){
	if (now == nill) return;
	//printf("key:%d\n", now->key);
	stack[++top] = now;
	Find(now->p);
}

inline void Update(int l, int r){
	//    printf("l:%d  r:%d\n", l, r);
	Tnode a, b, c;
	Split(root, a, b, l - 1);
	//    printf("a:%d   b:%d \n", a ->size, b ->size );
	Split(b, b, c, r - l + 1);
	//    printf("a:%d  b:%d  c:%d\n", a - node, b - node, c - node);
	swap(b->l, b->r);
	b->lazy ^= 1;
	Merge(b, b, c);
	Merge(root, a, b);
}

inline int FindKth(Tnode now){
	top = 0;
	Find(now);
	int ret = 0;
	while (top){
		now = stack[top--];
		PushDown(now);
		if (top > 0 && now->r == stack[top]) ret += now->l->size + 1;
	}
	ret += now->l->size + 1;
	return ret;
}

inline void dfs(Tnode now){
	if (now == nill) return;
	dfs(now->l);
	printf("%d", now->key);
	dfs(now->r);
}

int main(){
#ifdef ACM
	freopen("input.txt", "r", stdin);
#endif
	//freopen("output.txt", "w", stdout);
	while (scanf("%d", &n) != EOF){
		Build();
		for (int i = 1; i <= n; i++){
			scanf("%d", &arr[i].h);
			arr[i].id = i;
			pos[i] = NewNode(arr[i].h);
			Merge(root, root, pos[i]);
		}
		/*dfs(root);
		puts("");*/
		sort(arr + 1, arr + 1 + n);
		for (int i = 1; i <= n; i++){
			int kth = FindKth(pos[arr[i].id]);
			printf("%d%c", kth, i == n ? '\n' : ' ');
			//printf("i:%d  kth:%d\n", arr[i].h, kth);
			Update(i, kth);
			//printf("root:%d\n", root - node);
			/*dfs(root);
			puts("");*/
		}
	}
	return 0;
}

你可能感兴趣的:(可合并的TREAP)