Frequent values
Time Limit : 4000/2000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 22 Accepted Submission(s) : 9
Problem Description
You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.
Input
<p>The input consists of several test cases. Each test case starts with a line containing two integers <strong>n</strong> and <strong>q</strong> (<i>1 ≤ n, q ≤ 100000</i>). The next line contains <strong>n</strong> integers <strong>a<sub>1</sub> , ... , a<sub>n</sub></strong> (<i>-100000 ≤ a<sub>i</sub> ≤ 100000</i>, for each <i>i ∈ {1, ..., n}</i>) separated by spaces. You can assume that for each <i>i ∈ {1, ..., n-1}: a<sub>i</sub> ≤ a<sub>i+1</sub></i>. The following <strong>q</strong> lines contain one query each, consisting of two integers <strong>i</strong> and <strong>j</strong> (<i>1 ≤ i ≤ j ≤ n</i>), which indicate the boundary indices for the <br>query.</p><p>The last test case is followed by a line containing a single <i>0</i>.</p>
Output
<p>For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.</p>
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
PKU
题意
给一个长度为N的序列,求l~r之间出现最多的数字出现的次数
思路:
先将数据 进行离散化,然后用一个数组记录每个位置的离散之后得数·,因为题目要求是非递减的,所以这给题目解决提供很大的方便,然后就是用线段树求某个离散数所包括的区间范围内的最大的出现个数。离散化的优点就是线段树数组的大小可以开的很小。看代码吧:
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)
const int maxn=100005;
int n;
int a[maxn],b[maxn];
//b记录每个离散得到的点对应区间的端点
int ans;
struct node{
int start,end;
}ss[maxn];
struct Tree{
int l,r;
int maxx;
}tree[maxn<<2];
void build(int l,int r,int pos){ //建树注意最大值的求法
tree[pos].l=l;
tree[pos].r=r;
if(l==r){
tree[pos].maxx=ss[l].end-ss[l].start+1;
return;
}
int mid=(l+r)>>1;
build(l,mid,L(pos));
build(mid+1,r,R(pos));
tree[pos].maxx=max(tree[L(pos)].maxx,tree[R(pos)].maxx);
}
//区间求最值,套模板即可
int query(int l,int r,int pos){
if(tree[pos].l==l&&tree[pos].r==r)
return tree[pos].maxx;
else
{
int mid=(tree[pos].l+tree[pos].r)>>1;
if(r<=mid)return query(l,r,L(pos));
else if(l>mid)return query(l,r,R(pos));
else return max(query(l,mid,L(pos)),query(mid+1,r,R(pos)));
}
}
int main(){
// ios::sync_with_stdio(false);
int q;
int pre;
int i,j;
while(~scanf("%d",&n)){
if(n==0)break;
scanf("%d",&q);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
pre=100001;
ans=0;//ans是记录离散化后形成的数的个数
for(i=1;i<=n;i++){
if(a[i]!=pre){
pre=a[i];
ans++;
ss[ans].start=i;
ss[ans].end=i;
}
else
ss[ans].end=i;
b[i]=ans;//标记原序列中每个下标对应离散后的点
}
build(1,ans,1);
while(q--){
int x,y,xx,yy;
scanf("%d%d",&x,&y);
if(x==y){
printf("1\n");
continue;
}
xx=b[x],yy=b[y];//下标为x和y的点离散后对应的点
if(xx==yy){ //位于同一个离散数的区间内,离散后的点是用一个点,说明[x,y]为同一个点集
printf("%d\n",y-x+1);
continue;
}
else{//求三部分以上的情况,不是同一个点集,就分为三部分,第二部分的点集最大值用线段树来求
int ans1=ss[xx].end-x+1;
int ans2=y-ss[yy].start+1;
int ans3=0;
if(yy>xx+1)
ans3=query(xx+1,yy-1,1);
printf("%d\n",max(max(ans1,ans2),ans3));
continue;
}
}
}
return 0;
}