Frequent values(线段树+离散化)

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
 

Statistic |  Submit |  Back

题意

给一个长度为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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值