poj3368

题意:给出一个不降数列,并多次询问某区间内出现次数最多的数字在该区间内的出现频数。

分析:线段树的题,似乎也可以用rmq. 这个题的难点在于查询,因为首先要把相同的数据归为一块(unique),并标记每个块中有多少个数字。

由于这个数列是不降的,所以相同的数字在数列里一定是连续出现的。

建树,并将每个块插入的树中作为一个叶子节点。

这样查询时相当于l,r边界与题中给出的i,j是两个概念。所以此线段树需要两重边界。询问的时候要做特殊的边界处理。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

#define maxn 101

struct node
{
	int s, e;
	node *left, *right;
	int num, value, num1;
} tree[maxn * 2], f[maxn];

int n, q, ncount;

void buildtree(node *proot, int s, int e)
{
	proot->s = s;
	proot->e = e;
	proot->value = -1;
	proot->num = 0;
	if (s == e)
		return;
	ncount++;
	proot->left = tree + ncount;
	ncount++;
	proot->right = tree + ncount;
	buildtree(proot->left, s, (s + e) / 2);
	buildtree(proot->right, (s + e) / 2 + 1, e);
}

void init()
{
	int j = 0, a;
	scanf("%d", &f[0].value);
	f[0].num = 1;
	f[0].num1 = 1;
	for (int i = 1; i < n; i++)
	{
		scanf("%d", &a);
		if (a == f[j].value)
			f[j].num++,f[j].num1++;
		else
		{
			j++;
			f[j].num = 1;
			f[j].num1 = f[j - 1].num1 + 1;
			f[j].value = a;
		}
	}
	n = j;
}

void insert(node *proot, node &a, int i)
{
	if (a.num > proot->num)
	{
		proot->num = a.num;
		proot->value = a.value;
	}
	if (proot->s == proot->e)
		return;
	int mid = (proot->s + proot->e) / 2;
	if (i <= mid)
		insert(proot->left, a, i);
	else
		insert(proot->right, a, i);
}

void query(node *proot, int i, int j, node &a)
{
	int mid = (proot->s + proot->e) / 2;
	int as, ae;
	if (proot->s == 0)
		as = 1;
	else
		as = f[proot->s - 1].num1 + 1;
	ae = f[proot->e].num1;
	if (i == as && j == ae)
	{
		a.num = proot->num;
		a.value = proot->value;
		return;
	}
	if (proot->s == proot->e)
	{
		a.num = j - i + 1;
		a.value = proot->value;
		return;
	}
	node b, c;
	b.num = 0;
	c.num = 0;
	if (i <= f[mid].num1)
		query(proot->left, i, min(f[mid].num1, j), b);
	if (j > f[mid].num1)
		query(proot->right, max(f[mid].num1 + 1, i), j, c);
	if (b.num > c.num)
	{
		a.num = b.num;
		a.value = b.value;
	}
	else
	{
		a.num = c.num;
		a.value = c.value;
	}
}

int main()
{
	//freopen("D:\\t.txt", "r", stdin);
	while (scanf("%d", &n) != EOF && n != 0)
	{
		scanf("%d", &q);
		ncount = 0;
		init();
		buildtree(tree, 0, n);
		for (int i = 0; i <= n; i++)
			insert(tree, f[i], i);
		for (int i = 0; i < q; i++)
		{
			int a, b;
			node temp;
			scanf("%d%d", &a, &b);
			query(tree, a, b, temp);
			printf("%d\n", temp.num);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/rainydays/p/1949529.html