ZOJ2112-Dynamic Rankings

本文介绍了一种使用树状数组和线段树实现的高效算法,用于处理动态排名查询及数值更新的问题。该算法能够在大规模数据集上快速完成对特定区间内第k小元素的查询,并支持对序列中任意位置的数值进行修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dynamic Rankings

Time Limit: 10 Seconds       Memory Limit: 32768 KB

The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

Your task is to write a program for this computer, which

- Reads N numbers from the input (1 <= N <= 50,000)

- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.


Input

The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

Q i j k or
C i t

It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

There're NO breakline between two continuous test cases.


Output

For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

There're NO breakline between two continuous test cases.


Sample Input

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


Sample Output

3
6
3
6


(adviser)
Site: http://zhuzeyuan.hp.infoseek.co.jp/index.files/our_contest_20040619.htm


Author:  XIN, Tao
Source:  Online Contest of Christopher's Adventure


题意:给你一个序列,有n个数,两种操作,Q:询问在[l,r]内的第k大的数,C:更改第i个数位x

解题思路:主席数保存初始序列,树状数组+线段树记录修改操作


#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>  
#include <cctype>  
#include <map>  
#include <cmath>  
#include <set>  
#include <stack>  
#include <queue>  
#include <vector>  
#include <bitset>  
#include <functional>  

using namespace std;

#define LL long long  
const int INF = 0x3f3f3f3f;
const int maxn = 60505;
const int maxm = 1000505;
const int lowbit(int k) { return k&-k; }

int t, n, m, q, a[maxn], b[maxn], c[maxn], tot1, tot2;
char ch[2];
int L1[maxm], R1[maxm], sum1[maxm], s1[maxn];
int L2[maxm], R2[maxm], sum2[maxm], s2[maxn];

struct node
{
	int f, l, r, k;
}p[maxn];

void build(int pre, int &now, int l, int r, int k)
{
	sum1[now = ++tot1] = sum1[pre] + 1;
	if (l == r) { L1[now] = R1[now] = 0; return; }
	int mid = (l + r) >> 1;
	L1[now] = L1[pre], R1[now] = R1[pre];
	if (mid >= k) build(L1[pre], L1[now], l, mid, k);
	else build(R1[pre], R1[now], mid + 1, r, k);
}

void add(int &k, int l, int r, int p, int val)
{
	if (!k) k = ++tot2, L2[k] = R2[k] = sum2[k] = 0;
	sum2[k] += val;
	if (l == r) return;
	int mid = (l + r) >> 1;
	if (p <= mid) add(L2[k], l, mid, p, val);
	else add(R2[k], mid + 1, r, p, val);
}

void Insert(int k, int p, int val)
{
	for (int i = k; i <= n; i += lowbit(i)) add(s2[i], 1, m - 1, p, val);
}

int query(int l, int r, int k)
{
	int A = 0, B = 0, a[50], b[50], u = s1[l - 1], v = s1[r];
	for (int i = l - 1; i; i -= lowbit(i)) a[A++] = s2[i];
	for (int i = r; i; i -= lowbit(i)) b[B++] = s2[i];
	for (l = 1, r = m - 1; l < r;)
	{
		int sum = 0, mid = (l + r) >> 1;
		for (int i = 0; i < B; i++) sum += sum2[L2[b[i]]];
		for (int i = 0; i < A; i++) sum -= sum2[L2[a[i]]];
		sum += sum1[L1[v]] - sum1[L1[u]];
		if (k <= sum)
		{
			for (int i = 0; i < B; i++) b[i] = L2[b[i]];
			for (int i = 0; i < A; i++) a[i] = L2[a[i]];
			u = L1[u];  v = L1[v]; r = mid;
		}
		else
		{
			for (int i = 0; i < B; i++) b[i] = R2[b[i]];
			for (int i = 0; i < A; i++) a[i] = R2[a[i]];
			l = mid + 1, k -= sum, u = R1[u], v = R1[v];
		}
	}
	return l;
}

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &q);
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
		int nn = n;
		for (int i = 1; i <= q; i++)
		{
			scanf("%s", ch);
			if (ch[0] == 'Q') scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].k), p[i].f = 1;
			else
			{
				p[i].f = 0, p[i].k = ++nn;
				scanf("%d%d", &p[i].l, &p[i].r);
				b[nn] = a[nn] = p[i].r;
			}
		}
		sort(a + 1, a + nn + 1);
		m = unique(a + 1, a + nn + 1) - a;
		for (int i = 1; i <= nn; i++) c[i] = lower_bound(a + 1, a + m, b[i]) - a;
		tot1 = L1[0] = R1[0] = sum1[0] = tot2 = s1[0] = 0;
		for (int i = 1; i <= n; i++) build(s1[i - 1], s1[i], 1, m - 1, c[i]);
		for (int i = 0; i <= n; i++) L2[i] = R2[i] = sum2[i] = 0;
		for (int i = 1; i <= q; i++)
		{
			if (p[i].f)
			{
				int ans = query(p[i].l, p[i].r, p[i].k);
				printf("%d\n", a[ans]);
			}
			else if (c[p[i].l] != c[p[i].k])
			{
				Insert(p[i].l, c[p[i].l], -1);
				Insert(p[i].l, c[p[i].k], 1);
				c[p[i].l] = c[p[i].k];
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值