树套树 Dynamic Rankings 动态排名 BZOJ 1901

1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 867  Solved: 350
[Submit][Status][Discuss]

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。 你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。 第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。 接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

20%的数据中,m,n≤100;
40%的数据中,m,n≤1000;
100%的数据中,m,n≤10000。


疼,上手第一个题解就树套树

思路:
由于是维护区间,于是很容易想到用线段树
但是线段树不具备动态维护区间第k大值的能力(线段树可以动态修改,但查询效率。。。)
于是就不难想到用平衡树充当并维护线段树中的线段,这样可以做到对于一个给定的值,查询在这个线段中有多少个比它小的值
有了这个功能,我们就可以二分答案,放入树套树中查询

源代码:
#include <cstdio>
#include <algorithm>
#include <cstring>

const int Maxn = 10010;

class Splay_Node
{
public:
	int data, size;
	Splay_Node *lch, *rch, *fa;
	Splay_Node()
	{
		data = -100000000;
		size = 0;
		lch = rch = NULL;
	}
	~Splay_Node(){}
};
void update(Splay_Node *x)
{
	x -> size = 1;
	if(x -> lch != NULL) x -> size += x -> lch -> size;
	if(x -> rch != NULL) x -> size += x -> rch -> size;
}
void Zig(Splay_Node *x)
{
	Splay_Node *f, *g;
	f = x -> fa, g = f -> fa;
	if(g && f == g -> lch) g -> lch = x;
	else if(g && f == g -> rch) g -> rch = x;
	x -> fa = g;
	f -> lch = x -> rch;
	if(x -> rch) x -> rch -> fa = f;
	x -> rch = f;
	f -> fa = x;
	update(f);
	update(x);
}
void Zag(Splay_Node *x)
{
	Splay_Node *f, *g;
	f = x -> fa, g = f -> fa;
	if(g && f == g -> lch) g -> lch = x;
	else if(g && f == g -> rch) g -> rch = x;
	x -> fa = g;
	f -> rch = x -> lch;
	if(x -> lch) x -> lch -> fa = f;
	x -> lch = f;
	f -> fa = x;
	update(f);
	update(x);
}
class Splay
{
public:
	Splay_Node *t;
	Splay_Node *root;
	Splay_Node **recycle_bin;
	~Splay(){}
	int tot, top;
	Splay()
	{
		root = NULL;
		tot = 0;
		top = -1;
	}
	void resize(const int &size)
	{
		t = new Splay_Node [size];
		recycle_bin = new Splay_Node* [size];
	}
	void splay(Splay_Node* x)
	{
		Splay_Node *f, *g;
		root = x;
		while(x -> fa)
		{
			f = x -> fa, g = f -> fa;
			if(g == NULL)
			{
				f -> rch == x ? Zag(x) : Zig(x);
			}
			else
			{
				if(g -> lch == f)
				{
					if(f -> lch == x)
					{
						Zig(f);
						Zig(x);
					}
					else
					{
						Zag(x);
						Zig(x);
					}
				}
				else
				{
					if(f -> rch == x)
					{
						Zag(f);
						Zag(x);
					}
					else
					{
						Zig(x);
						Zag(x);
					}
				}
			}
		}
	}
	Splay_Node* alloc()
	{
		if(top == -1)
		{
			return &t[tot++];
		}
		else
		{
			return recycle_bin[top--];
		}
	}
	void insert(int x, Splay_Node* &cur, Splay_Node *fa)
	{
		if(cur == NULL)
		{
			cur = alloc();
			cur -> data = x;
			cur -> lch = cur -> rch = NULL;
			cur -> size = 1;
			cur -> fa = fa;
		}
		else
		{
			insert(x, x < cur -> data ? cur -> lch : cur -> rch, cur);
			update(cur);
		}
	}
	void build(int *arr, int size)
	{
		for(int i = 0; i < size; ++i)
			insert(arr[i], root, NULL);
	}
	int Query(int x, Splay_Node *cur)
	{
		if(cur == NULL) return 0;
		if(cur -> data >= x)
		{
			return Query(x, cur -> lch);
		}
		else
		{
			if(cur -> lch)
			{
				return cur -> lch ->size + 1 + Query(x, cur -> rch);
			}
			else
			{
				return 1 + Query(x, cur -> rch);
			}
		}
	}
	void del(int val, Splay_Node *cur)
	{
		while(cur -> data != val)
		{
			if(cur -> data > val) cur = cur -> lch;
			else cur = cur -> rch;
		}
		splay(cur);
		root = cur -> lch;
		if(cur -> lch) cur -> lch -> fa = NULL;
		if(cur -> rch) cur -> rch -> fa = NULL;
		Splay_Node *tmp = cur -> lch;
		if(tmp == NULL)
		{
			root = cur -> rch;
			if(cur->rch) cur -> rch -> fa = NULL;
		}
		else
		{
			while(tmp -> rch)
			{
				tmp = tmp -> rch;
			}
			splay(tmp);
			root -> rch = cur -> rch;
			if(cur -> rch) cur -> rch -> fa = root;
		}
		if(root) update(root);
		recycle_bin[++top] = cur;
	}
};

class segtree
{
public:
	Splay node;
	int l, r, lch, rch;
	void modify(int pre_val, int new_val)
	{
		node.del(pre_val, node.root);
		node.insert(new_val, node.root, NULL);
	}
};

segtree t[Maxn * 4];
int v[Maxn];

void seg_build(int l, int r, int p)
{
	t[p].node.resize(2 * (r - l + 1));
	t[p].l = l, t[p].r = r;
	t[p].node.build(&v[l], r - l + 1);
	if(l == r)
	{
		t[p].lch = t[p].rch = 0;
		return;
	}
	t[p].lch = p << 1;
	t[p].rch = p << 1 | 1;
	int mid = l + r >> 1;
	seg_build(l, mid, p << 1);
	seg_build(mid + 1, r, p << 1 | 1);
}

int Query(int l, int r, int p, int v)
{
	if(t[p].l == l && t[p].r == r)
	{
		return t[p].node.Query(v, t[p].node.root);
	}
	else
	{
		int mid = t[p].l + t[p].r >> 1;
		if(r <= mid)
		{
			return Query(l, r, p << 1, v);
		}
		else if(l > mid)
		{
			return Query(l, r, p << 1 | 1, v);
		}
		else
		{
			return Query(l, mid, p << 1, v) + Query(mid + 1, r, p << 1 | 1, v);
		}
	}
}



void seg_modify(int pos, int new_val)
{
	int p = 1;
	int mid;
	do
	{
		t[p].modify(v[pos], new_val);
		mid = t[p].l + t[p].r >> 1;
		if(pos <= mid) p = t[p].lch;
		else p = t[p].rch;
	}while(p);
}

int main()
{
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	int n, m, x, y, z;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
	seg_build(1, n, 1);
	for(int i = 0; i < m; ++i)
	{
		char o;
		while(o = getchar(), o != 'Q' && o != 'C');
		if(o == 'Q')
		{
			scanf("%d%d%d", &x, &y, &z);
			--z;
			int l = 0, r = 1000000010, mid;
			while(l <= r)
			{
				mid = l + r >> 1;
				int s = Query(x, y, 1, mid);
				if(s > z)
				{
					if(Query(x, y, 1, mid - 1) <= z)
					{
						printf("%d\n", mid - 1);
						break;
					}
					r = mid - 1;
				}
				else
				{
					l = mid + 1;
				}
			}
		}
		else
		{
			scanf("%d%d", &x, &y);
			seg_modify(x, y);
			v[x] = y;
		}
	}
	return 0;
}



发布了1 篇原创文章 · 获赞 0 · 访问量 896
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览