POJ 1442 Black Box (数据结构)

题目类型  数据结构

题目意思
给出最多30000个数 并最多问30000次当考虑前 x 个数时第 y 小的数是多少 其中 y 从 1-> 30000, 对应的 x 输入给出

解题方法
可以用线段树, treap, splay 等数据结构做

参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
treap
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstdlib>

using namespace std;

const int maxn = 30000 + 10;
int a[maxn], b[maxn];

struct Node {
	Node * ch[2];
	int r;
	int v;
	int s;
	Node(int v) : v(v) { ch[0] = ch[1] = NULL; r = rand(); s = 1; }
	int cmp(int x) const {
		if(x == v) return -1;
		return x < v ? 0 : 1;
	}
	void maintain() {
		s = 1;
		if(ch[0] != NULL) s += ch[0]->s;
		if(ch[1] != NULL) s += ch[1]->s;
	}
};

struct Treap {
	Node * rt;
	Treap() { rt = NULL; }
	
	void rotate(Node* & o, int d) {
		Node * k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; 
		o->maintain(); k->maintain();
		o = k;
	}

	void insert(Node* & o, int x) {
		if(o == NULL) o = new Node(x);
		else {
			int d = (x > o->v ? 1 : 0); // 相等放左儿子那边
			insert(o->ch[d], x);
			if(o->ch[d]->r > o->r) rotate(o, d ^ 1);
		}
		o->maintain();
	}

	void remove(Node* & o, int x) {
		int d = o->cmp(x);
		if(d == -1) {
			Node * u = o;
			if(o->ch[0] != NULL && o->ch[1] != NULL) {
				int d2 = (o->ch[0] > o->ch[1] ? 1 : 0);
				rotate(o, d2); remove(o->ch[d2], x);
			}
			else {
				if(o->ch[0] == NULL) o = o->ch[1]; else o = o->ch[0];
				delete u;
			}
		}
		else remove(o->ch[d], x);
		if(o != NULL) o->maintain();
	}

	int kth(Node* & o, int k) { // 第k小
		Node * t = o;
		while(1) {
			int s = t->ch[0] == NULL ? 0 : t->ch[0]->s;
			if(k <= s) t = t->ch[0];
			else if(k == s + 1) return t->v;
			else { k -= s + 1; t = t->ch[1]; }
		}
	}

	void removetree(Node* & x) {
		if(x == NULL) return ;
		if(x->ch[0] != NULL) removetree(x->ch[0]);
		if(x->ch[1] != NULL) removetree(x->ch[1]);
		delete x;
		x = NULL;
	}
};

int main() {
	freopen("in", "r", stdin);
  srand(time(0));

	int n, m;
	while(scanf("%d%d", &m, &n) != EOF) {
		for( int i=0; i<m; i++ ) scanf("%d", &a[i]);
		for( int i=0; i<n; i++ ) scanf("%d", &b[i]);
		Treap trp;
		int i = 0;
		int j = 0;
		int tj = 0;
		for( int i=0; i<n; i++ ) {
			while(tj < b[i]) {
				trp.insert(trp.rt, a[tj]);
				tj++;
			}
			printf("%d\n", trp.kth(trp.rt, i+1));
		}
		trp.removetree(trp.rt);
	}
	return 0;
}

splay
#include <iostream>
#include <cstdio>

using namespace std;

const int maxn = 30000 + 10;
int a[maxn], b[maxn];

struct Node {
	Node * ch[2];
	int v;
	int s;
	Node(int v) : v(v) { ch[0] = ch[1] = NULL; s = 1; }
	int cmp(int x) const {
		if(x == v) return -1;
		return x < v ? 0 : 1;
	}
	void maintain() {
		s = 1;
		if(ch[0] != NULL) s += ch[0]->s;
		if(ch[1] != NULL) s += ch[1]->s;
	}
};

struct Splay {
	Node * rt;
	Splay() { rt = NULL; }
	void rotate(Node* & o, int d) {
		Node * k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; 
		o->maintain(); k->maintain();
		o = k;
	}

	void splay(Node* & o, int x) {
		int d = o->cmp(x);
		if(d != -1) {
			Node * p = o->ch[d];
			int d2 = p->cmp(x);
			if(d2 != -1) {
				splay(p->ch[d2], x);
				if(d == d2) rotate(o, d^1); else rotate(o->ch[d], d);
			}
			rotate(o, d^1);
		}
	}

	void insert(Node* & o, int x) {
		if(o == NULL) o = new Node(x);
		else {
			int d = x > o->v ? 1 : 0; // 相等放左儿子那边 
			insert(o->ch[d], x);
			o->maintain();
		}
	}

	int findMax(Node* & o) {
		Node * t = o;
		while(t->ch[1] != NULL) t = t->ch[1];
		splay(o, t->v);
		return o->v;
	}

	void remove(int x) {
		splay(rt, x);

		Node * t = rt;
		if(rt->ch[0] == NULL) {
			rt = rt->ch[1];
			delete t;
		}
		else {
			findMax(rt->ch[0]);
			rt->ch[0]->ch[1] = rt->ch[1];
			rt = rt->ch[0];
			rt->maintain();
			delete t;
		}
	}

	int kth(Node* & o, int k) { // 第k小
		Node * t = o;
		while(1) {
			int s = t->ch[0] == NULL ? 0 : t->ch[0]->s;
			if(k <= s) t = t->ch[0];
			else if(k == s + 1) return t->v;
			else { k -= s + 1; t = t->ch[1]; }
		}
	}

	void removetree(Node* & o) {
		if(o == NULL) return ;
		if(o->ch[0] != NULL) removetree(o->ch[0]);
		if(o->ch[1] != NULL) removetree(o->ch[1]);
		delete o;
		o = NULL;
	}
};

int main() {
	int n, m;
	scanf("%d%d", &m, &n);
	for( int i=0; i<m; i++ ) scanf("%d", &a[i]);
	for( int i=0; i<n; i++ ) scanf("%d", &b[i]);
	Splay spy;
	int i = 0;
	int tj = 0;
	for( int i=0; i<n; i++ ) {
		while(tj < b[i]) {
			spy.insert(spy.rt, a[tj]);
			spy.splay(spy.rt, a[tj]);
			tj++;
		}
		int ans = spy.kth(spy.rt, i+1);
		spy.splay(spy.rt, ans);
		printf("%d\n", ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值