POJ_3368_Frequent values_线段树/ST稀疏表

来源:互联网 发布:sequoiadb巨杉数据库 编辑:程序博客网 时间:2024/05/20 06:06
头疼

题意

给一个n长度的a int数组,且a数组为不下降数列,询问q次,每次询问l到r之间出现次数最多的数字出现了多少次。

IO

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.

分析

一开始一看这题询问区间内值的分布情况,就想用主席树,结果到了询问的时候仔细想想又发现主席树破不了。
总是出现这样的问题就是过于注重分析如何维护数据结构保持consistant,而不认真地想想数据结构维护什么数据才能得到答案。
这题把问题转化成了RMQ问题,计算每个数值出现的次数,然后把这个数组按照数字出现的顺序排成一个新的数组,并且记录原数组中每个位置对应新数组中哪个位置,记录新数组每个数对应原数组的区间范围,由于是不下降数列,这些很自然。
然后线段树或者ST稀疏表维护RMQ信息,对于一次查询l,r,先修改l和r对应新数组位置的值,因为可能正好卡在一串相等数字的中间,然后查询对应区间的RMQ信息,再把信息改回来。
还有另一种办法是比较l位置和l位置值结束位置、r位置和r位置值开始位置、l值结束位置和r值开始位置之间的RMQ信息,这样就不需要更新操作。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define MXN 100010int da[MXN];int n,q;int a[MXN],st[MXN],ed[MXN],mp[MXN];int cnt;int ll[MXN<<2],rr[MXN<<2],mx[MXN<<2];void build(int id,int l,int r){    ll[id]=l,rr[id]=r;    if(l==r){        mx[id]=da[l];        return;    }    int m=(l+r)>>1,ls=id<<1,rs=ls|1;    build(ls,l,m);    build(rs,m+1,r);    mx[id]=max(mx[ls],mx[rs]);}void update(int id,int loc,int num){    if(ll[id]==rr[id]){        mx[id]=num;        return;    }    int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;    if(loc<=m)  update(ls,loc,num);    else    update(rs,loc,num);    mx[id]=max(mx[ls],mx[rs]);}int query(int id,int l,int r){    if(ll[id]==l&&rr[id]==r)    return mx[id];    int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;    if(r<=m)    return query(ls,l,r);    else if(l>m)    return query(rs,l,r);    else    return max(query(ls,l,m),query(rs,m+1,r));}int main(){    while(scanf("%d",&n)!=EOF&&n){        scanf("%d",&q);        cnt=-1;        int pre=-1000000;        for(int i=1;i<=n;++i){            scanf("%d",a+i);            if(a[i]!=pre){                if(pre!=-1000000){                    ed[cnt]=i-1;                }                ++cnt;                da[cnt]=0;                st[cnt]=i;                pre=a[i];            }            mp[i]=cnt;            ++da[cnt];        }        ++cnt;        build(1,0,cnt-1);        for(int Q=0;Q<q;++Q){            int l,r;            scanf("%d%d",&l,&r);            int tl=mp[l],tr=mp[r];            if(tl==tr){                printf("%d\n",r-l+1);                continue;            }            update(1,tl,ed[tl]-l+1);            update(1,tr,r-st[tr]+1);            printf("%d\n",query(1,tl,tr));            update(1,tl,ed[tl]-st[tl]+1);            update(1,tr,ed[tr]-st[tr]+1);        }    }    return 0;}
0 0
原创粉丝点击