POJ 3368 Frequent values(线段树+离散化)

思路:

首先对给出的序列进行离散化统计,将相同的数字压缩成一个节点,然后统计出这个压缩后的节点在原序列中起点和终点的位置,以及出现的次数等。当然也要记录原数字在离散化后的序列中的位置。
之后就是查询,比方说[a,b]
1.如果a,b属于同一个组,那么区间长度就是我们想要的答案 b-a+1;
2.如果a,b组号相差1,说明该区间被中间截断了,只要分别研究两侧的区间,取大值即可Max(c-a+1,b-c) ---其中c是中间点---
3.如果a,b组号相差大于1,先取出两侧进行研究,取大值,然后再用线段树,算出中间区间的最大值,与刚才的那个数比较,取出最大值即可。

 

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 100005;

struct Point
{
	int left;
	int right;
	int num;
	int count;
}p[MAXN];

int n, q, t, len;
int a[MAXN], hash[MAXN];

struct SegNode
{
	int left;
	int right;
	int num;
	int count;
	SegNode* lchild;
	SegNode* rchild;

	void Build(int l, int r);
	int Query(int l, int r);
}tree[MAXN*2], *root = tree;

void Init()
{
	int i;
	for (i = 1; i <= n; i++) scanf("%d", &a[i]);
	p[1].left = 1;
	p[1].right = 1;
	p[1].num = a[1];
	p[1].count = 1;
	hash[1] = 1;
	for (t = 1, i = 2; i <= n; i++)
	{
		if (a[i] == a[i-1])
		{
			p[t].count++;
			p[t].right = i;
		}
		else
		{
			t++;
			p[t].left = i;
			p[t].right = i;
			p[t].num = a[i];
			p[t].count = 1;
		}
		hash[i] = t;
	}
}

void SegNode::Build(int l, int r)
{
	left = l;
	right = r;
	if (left == right)
	{
		num = p[left].num;
		count = p[left].count;
		lchild = rchild = NULL;
		return;
	}
	
	int mid = (l+r)>>1;
	lchild = &tree[len++];
	lchild->Build(l, mid);
	rchild = &tree[len++];
	rchild->Build(mid+1, r);

	if (lchild->count > rchild->count)
	{
		num = lchild->num;
		count = lchild->count;
	}
	else
	{
		num = rchild->num;
		count = rchild->count;
	}
}

int SegNode::Query(int l, int r)
{
	if (l == left && r == right) return count;
	int mid = (left+right) >> 1;
	if (r <= mid) return lchild->Query(l, r);
	else if (l > mid) return rchild->Query(l, r);
	else
	{
		int tl = lchild->Query(l, mid);
		int tr = rchild->Query(mid+1, r);
		return tl > tr ? tl : tr;
	}
}

int Solve(int a, int b)
{
	if (hash[a] == hash[b]) return b-a+1;
	else if (hash[a]+1 == hash[b])
	{
		int ta = p[hash[a]].right - a + 1;
		int tb = b - p[hash[b]].left + 1;
		return ta > tb ? ta : tb;
	}
	else
	{
		int ta = p[hash[a]].right - a + 1;
		int tb = b - p[hash[b]].left + 1;
		int qy = root->Query(hash[a]+1, hash[b]-1);
		int ans = ta > tb ? ta : tb;
		return ans > qy ? ans : qy;
	}
}

int main()
{
	int a, b;
	while (scanf("%d", &n) != EOF, n)
	{
		scanf("%d", &q);
		Init();
		len = 1; root->Build(1, t);
		while (q--)
		{
			scanf("%d%d", &a, &b);
			printf("%d\n", Solve(a, b));
		}
	}
}
posted @ 2010-08-19 13:29  笨熊蜗居地  阅读(528)  评论(0编辑  收藏  举报