poj 3368 又一线段树

本文介绍了一种高效查询区间内重复数字最大次数的方法,适用于递增序列。通过哈希表和二叉树实现,提供了三种查询场景的解决方案。

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

这一个题目是求一个区间内重复数字的最大次数。

这题有一个特点,数字是递增滴,相同的数字肯定是连续的。

将相同的数字看做一个部分,hash保存每个数字属于哪个部分。对所有的部分建一颗二叉树,保存此区间内最大的重复数字的个数。

 

查询的时候分3中情况

1 在同一个部分,直接 尾 - 头 + 1就是结果

2 只差一个部分,分开算,在各个部分里面重复多少次,比较一下

3 中间有很多个部分,那么可以先根据2计算出两头的,在通过二叉树查询最大的重复数字个数

 

具体见代码,这题也可以用RMQ做,具体见下一篇:

// segment tree
#include <iostream>
using namespace std;

int arr[100010],hash[100010];

struct Part
{
	int s, e, cnt;
}part[100010];

struct Node
{
	int l, r, num;
}node[1000001];

int Max(int a, int b)
{
	return a >  b ? a : b;
}

void build(int l, int r, int u)
{
	node[u].l = l;
	node[u].r = r;
	if (l == r)
	{
		node[u].num = part[l].cnt;
		return ;
	}
	int mid = (l + r) >> 1;
	build(l, mid, 2 * u);
	build(mid + 1, r, 2  * u + 1);
	node[u].num = Max(node[2 * u].num , node[2 * u + 1].num );
}

int query(int l, int r, int u)
{
	if (node[u].l == l && node[u].r == r)
	{
		return node[u].num;
	}
	int mid = (node[u].l + node[u].r)>> 1;
	if (r <= mid)//all in left child tree
	{
		return query(l, r, 2 * u);
	}
	else if (l > mid)//all in right child tree
	{
		return query(l , r, 2 * u + 1);
	}
	else
	{
		return Max(query(l, mid, 2 * u), query(mid + 1, r, 2 * u + 1));
	}
}
int main()
{
	int n, q;
	while (scanf("%d", & n) && n)
	{
		scanf("%d", & q);
		for (int i = 1; i <= n; ++ i)
		{
			scanf("%d", & arr[i]);
		}
		memset(part, 0, sizeof(part));
		int id = 1;
		part[1].s = id;
		for (int i = 1; i <= n; ++ i)
		{
			part[id].cnt ++;
			hash[i] = id;
			if (arr[i] != arr[i + 1] || i == n)
			{
				part[id].e = i;
				++ id;
				part[id].s = i + 1;
			}
		}
		build(1, id - 1, 1);

		int a, b;
		while (q --)
		{
			scanf("%d %d", & a, & b);
			if (hash[a] == hash[b])//the same part
			{
				printf("%d\n", b - a + 1);
			}
			else// two situations
			{
				int n1 = part[hash[a]].e - a + 1;
				int n2 = b - part[hash[b]].s + 1;
				int n3 = 0;
				if (hash[b] - hash[a] > 1)
				{
					n3 = query(hash[a] + 1, hash[b] -  1, 1);
				}
				
				printf("%d\n", Max(Max(n1, n2),n3));
			}
		}
	}
	return 0;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值