题目链接:http://poj.org/problem?id=3368
Frequentvalues
Time Limit: 2000MS | Memory Limit: 65536K |
Total Submissions: 10917 | Accepted: 4004 |
Description
You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In additionto that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For eachquery, determine the most frequent value among the integers ai , ... , aj.
Input
The input consists of several test cases. Each test case startswith a line containing two integers nand q (1 ≤ n, q ≤ 100000). The nextline contains n integers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1,..., n}) separated by spaces. You can assume that for each i ∈ {1,..., n-1}: ai ≤ ai+1. The following q lines contain one query each,consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicatethe boundary indices for the
query.
The last test case is followed by a line containing a single 0.
Output
For each query, print one line with one integer: The number ofoccurrences of the most frequent value within the given range.
Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
Sample Output
1
4
3
Source
题意:求数组区间[i,j]中相同值的最大数量
解题思路:整体还是用线段树来解决,但是每个几点怎么存?实现先建一个结构体Note存放arr中连续相同子串的起点,终点,数量。在用一个pos存放该数组的第i个是属于Note中的哪一个。在针对pos数组进行建树,查找
代码:
#include <iostream>
#include<stdio.h>
#define maxn 1000006
using namespace std;
struct Tree
{
int l,r,rate;
}tree[maxn*4];
//用来存放每一个连续串的起点和终点和个数
struct Note
{
int s,e,count;
}note[maxn];
int arr[maxn],pos[maxn];
int max(int a,int b)
{
return a>b?a:b;
}
//建立线段树
void buildTree(int l,int r,int id)
{
tree[id].l = l;
tree[id].r = r;
if(l==r)
{
//表示第l个连续串的个数
tree[id].rate = note[l].count;
return ;
}
int mid = (l+r)/2;
buildTree(l,mid,id*2);
buildTree(mid+1,r,id*2+1);
tree[id].rate = max(tree[id*2].rate,tree[id*2+1].rate);
}
//查询树tree中l到r的最大连续个数
int findVal(int l,int r,int id)
{
int left = tree[id].l;
int right = tree[id].r;
if(l == left && r == right)
{//如果要查找的区间刚好是一个节点,那么直接返回该节点是rate值
return tree[id].rate;
}
int mid = (left+right)/2;
//查找左区间(表示要查找的右区间比mid还小)
if(r<=mid)
{
return findVal(l,r,id*2);
}
else if(l>=(mid+1))
{//查找右区间(表示要查找的左区间比mid+1还大)
return findVal(l,r,id*2+1);
}
else
{//要查找的区间在子区间的两边
return max(findVal(l,mid,2*id),findVal(mid+1,r,2*id+1));
}
}
int main()
{
int n,q;
int i;
while(true)
{
scanf("%d",&n);
if(n==0)
return 0;
scanf("%d",&q);
note[1].s=1;
for(i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
}
int id=1;
for(i=1;i<=n;i++)
{//计算每一个连续串的起点和终点和个数
pos[i] = id;
if(arr[i]!=arr[i+1] || i==n)
{
note[id].e = i;
note[id].count = i-note[id].s+1;
if(i!=n)
{
id++;
note[id].s = i+1;
}
}
}
//针对pos区间中建树
buildTree(1,id,1);
int a,b;
while(q--)
{
scanf("%d%d",&a,&b);
int t=0;
if(pos[a]==pos[b])
{//如果两个在相同区间内,那么直接计算
printf("%d\n",b-a+1);
}
else
{//如果两个在不同区间
if(pos[b]>(pos[a]+1))
{
//查找,t表示该pos[a]子串的下一个完整子串的长度到pos[b]的上一个子串中的最大个数
t = findVal(pos[a]+1,pos[b]-1,1);
}
/*
表示左边部分的最大数,比如-1,-1,1,1,1,1,3,10,10,10,查询区间(2,3),pos[a]的值表示是在哪个子串中
note[pos[a]].e表示在pos[a]这个子串中最后一个的位置
t1表示a到它这个子串结束后的长度,同理,b表示b这个子串的起始到b的长度
*/
int t1 = note[pos[a]].e-a+1;
int t2 = b-note[pos[b]].s+1;
printf("%d\n",max(t,max(t1,t2)));//三者取最大
}
}
}
return 0;
}