poj-3368-Frequent values-(线段树)

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

The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line 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 indicate the 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 of occurrences 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


题目给出一个不下降序列,查询时让求出区间内的出现次数最多的数出现的次数

题目问题在于怎么记录区间内数出现的次数,题目难点是将一个区间划分为左右子区间时怎么求,方法是用线段树来记录num是当前区间出现频率最多的数,lnum记录区间最左边的数在本区间内出现的次数,r记录区间最y右边的数在本区间内出现的次数,那么刚好在于数列中数是连续的,所以对左右子区间是否连续(左区间最右的数与右区间最左的数是否相同)进行判断处理

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
#define M 200005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int n,q;
struct node{
    int l,r,num,lnum,rnum; //num是当前区间出现频率最多的数,lnum记录区间最左边的数在本区间内出现的次数,r记录区间最y右边的数在本区间内出现的次数
}tree[M<<2];
int p[M];
inline void pushup(int rt)
{
    int l=tree[rt].l;
    int r=tree[rt].r;
    int m=(l+r)>>1;
    int temp;
    bool flag=false;
    if(p[tree[rt<<1].r]==p[tree[rt<<1|1].l])        //两个子区间能连续
        flag=true;

    if(flag)
        temp=tree[rt<<1].rnum+tree[rt<<1|1].lnum;   //两区间公共数的出现次数
    else
        temp=0;
    tree[rt].num=max(max(tree[rt<<1].num,tree[rt<<1|1].num),temp); 

    tree[rt].lnum=tree[rt<<1].lnum;      //区间lnum与左子区间的lnum相同
    if(flag&&tree[rt<<1].lnum==(m-l+1))  //子区间连续且左子区间中全为同一个数
        tree[rt].lnum+=tree[rt<<1|1].lnum;

    tree[rt].rnum=tree[rt<<1|1].rnum;
    if(flag&&tree[rt<<1|1].rnum==(r-m))
        tree[rt].rnum+=tree[rt<<1].rnum;
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    if(l==r)
    {
        tree[rt].num=tree[rt].lnum=tree[rt].rnum=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int query(int L,int R,int rt)
{
    if(L<=tree[rt].l&&tree[rt].r<=R)
    {
        return tree[rt].num;
    }
    int m=(tree[rt].l+tree[rt].r)>>1;
    int ret=-500000;
    if(R<=m) ret=max(ret,query(L,R,rt<<1));
    else if(L>m) ret=max(ret,query(L,R,rt<<1|1));
    else
    {
        ret=max(ret,query(L,m,rt<<1));
        ret=max(ret,query(m+1,R,rt<<1|1));
        if(p[tree[rt<<1].r]==p[tree[rt<<1|1].l])
        {
            int temp=min(tree[rt<<1].rnum,m-L+1)+min(tree[rt<<1|1].lnum,R-m);//子区间连续,要要查询区间范围是[L,R]
            ret=max(temp,ret);
        }
    }
    return ret;
}
int main()
{
    int a,b,i;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        scanf("%d",&q);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&p[i]);
        }
        build(1,n,1);
        while(q--)
        {
            scanf("%d%d",&a,&b);
            printf("%d\n",query(a,b,1));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值