洛谷P1801 黑匣子

题意

一系列add操作,给数列中增加一个数
一系列get操作,在某个add结束后,输出(get次数)名次的数
M<=200000

分析

是名次树功能的弱化版,可以用Treap完成。
Treap板子,跟随输入操作即可。
内存要开到二倍,少了会RE

代码

#include "cstdlib"
#include "iostream"
#include "cstdio"
#include "cstring"
#include <queue>
#include<iostream>

#define update( cur ) if(cur-> left-> size)cur-> size = cur -> left->size + cur -> right -> size , cur -> value = cur -> right -> value
#define new_Node( s , v , a , b ) ( & ( * st [ cnt++ ] = Node ( s , v , a , b) ) )
#define merge( a , b ) new_Node( a -> size + b -> size , b -> value , a , b )
#define ratio 4
int n,m, cnt, s, a;

inline int read()
{
	register int x = 0, v = 1, ch = getchar();
	while (!isdigit(ch))
	{
		if (ch == '-') v = -1;
		ch = getchar();
	}
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	return x * v;
}

class Node
{
public:
	int size, value;
	Node* left, * right;
	Node(int s, int v, Node* a, Node* b) : size(s), value(v), left(a), right(b) {}
	Node() {}
};
Node* root, * st[400010], t[400010], * null, * father;

inline void maintain(register Node* cur)
{
	if (cur->left->size > cur->right->size* ratio) cur->right = merge(cur->left->right, cur->right), st[--cnt] = cur->left, cur->left = cur->left->left;
	if (cur->right->size > cur->left->size* ratio) cur->left = merge(cur->left, cur->right->left), st[--cnt] = cur->right, cur->right = cur->right->right;
}
int find(int x, Node* cur)
{
	if (cur->size == 1) return cur->value;
	return x > cur->left->size ? find(x - cur->left->size, cur->right) : find(x, cur->left);
}

int rank(int x, Node* cur)
{
	if (cur->size == 1) return 1;
	return x > cur->left->value ? rank(x, cur->right) + cur->left->size : rank(x, cur->left);
}

void insert(int x, Node* cur)
{
	if (cur->size == 1) cur->left = new_Node(1, std::min(cur->value, x), null, null), cur->right = new_Node(1, std::max(cur->value, x), null, null);
	else insert(x, x > cur->left->value ? cur->right : cur->left);
	update(cur);
	maintain(cur);
}

void erase(int x, Node* cur)
{
	if (cur->size == 1) *father = cur == father->left ? *father->right : *father->left;
	else father = cur, erase(x, x > cur->left->value ? cur->right : cur->left);
	update(cur);
}
/*
read()函数可以读入一个数字
insert(a,root)是插入数a
erase(a,root)删除数a,有多个只删除一个
rank(a,root)返回a的名次
find(a,root)返回名次a的数
前驱find( rank( a , root ) - 1 , root )
后继find( rank( a + 1 , root ) , root )
*/
int ADD[200010], GET[200010];
int main()
{
	
	std::ios::sync_with_stdio(false);
	std::cin >> n >> m;
	for (register int i = 0; i < 400010; i++) st[i] = &t[i];
	null = new Node(0, 0, 0, 0);
	root = new Node(1, 2147483647, null, null);
	for (int i = 1; i <= n; i++)std::cin >> ADD[i];
	for (int i = 1; i <= m; i++)std::cin >> GET[i];
	int now = 1;int p = 1;//now是GET当前的下标,也是查询的排名,p是ADD的下标
	while (now<=m)
	{
		if (GET[now] >= p) {//还未到
			insert(ADD[p],root);
			p++;
		}
		else {
			printf("%d\n", find(now, root));
			now++;
		}
	}
	return 0;
}


发布了32 篇原创文章 · 获赞 0 · 访问量 1181

猜你喜欢

转载自blog.csdn.net/engineoid/article/details/104226777