UVA-11235 Frequent values(频繁出现的次数)【线段树或RMQ】

题目传送门

UVA-11235 Frequent values(频繁出现的次数)【线段树或RMQ】_第1张图片

题目大意:

给出一个非降序排列的整数数组a1,a2,a3,...an,你的任务是对于一系列询问(i,j),回答a[i],a[i+1],...a[j]中出现次数最多的值所出现的次数。

解题思路:

整个数组是非降序的,所有相等元素都会聚集到一起。这样就可以把整个数组进行游程编码,把整个数组分成若干段,用sum[i]表示第i段的数出现的次数,num[p],lft[p],rig[p],分别表示位置p所在段的编号和左右端点的位置。每次查询(L,R)的结果为以下3个部分的最大值:

  1. 从L到L所在段的右端点的元素个数(即rig[L]-L+1)
  2. 从R所在段的左端点到R的元素个数(即R-lft[R]+1)
  3. 中间第num[L]+1段到第num[R]-1段的sum的最小值

特殊情况,如果L和R在同一段中,则答案是R-L+1。

AC代码:

  • 解法一:线段树
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define inf 0x3f3f3f
typedef long long ll;
typedef unsigned long long ULL;
const int mod=1e9+7;
const int maxn=1e5+7;
int n,q,lft[maxn],rig[maxn],num[maxn];
int cnt,sum[maxn],a[maxn];
struct tree
{
    int L,R;
    int data;
}tr[maxn<<2];
void build(int l,int r,int i)
{
    tr[i].L=l;
    tr[i].R=r;
    if(l==r)
    {
        tr[i].data=sum[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    tr[i].data=max(tr[i<<1].data,tr[i<<1|1].data);
}
int query(int l,int r,int i)
{
    if(l>r)
        return 0;
    if(tr[i].L>=l&&tr[i].R<=r)
        return tr[i].data;
    int mid=(tr[i].L+tr[i].R)>>1;
    if(l>mid)
        return query(l,r,i<<1|1);//完全在右孩子区间
    if(r<=mid)
        return query(l,r,i<<1);//完全在左孩子区间
    return max(query(l,r,i<<1),query(l,r,i<<1|1));
}
int main()
{
    while(cin>>n&&n)
    {
        ms(sum);
        cnt=0;
        cin>>q;
        a[0]=inf;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            num[i]=a[i]==a[i-1]?cnt:++cnt;
            sum[cnt]++;
            if(a[i]==a[i-1]) lft[i]=lft[i-1];
            else lft[i]=i;
        }
        rig[n]=n;
        for(int i=n-1;i>=1;i--)
        {
            if(a[i]==a[i+1]) rig[i]=rig[i+1];
            else rig[i]=i;
        }
        build(1,cnt,1);
        while(q--)
        {
            int l,r;
            cin>>l>>r;
            if(num[l]==num[r])
            {
                cout<
  • 解法二:RMQ
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define mc(a,b) memcpy(a,b,sizeof(b))
#define inf 0x3f3f3f
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
typedef long long ll;
typedef unsigned long long ULL;
const int mod=1e9+7;
const int N=1e5+7;
int n,q;
int arr[N],num[N],lef[N],righ[N],sum[N];
int d[N][100];
void init_RMQ(int len)
{
    for(int i=1;i<=len;i++) d[i][0]=sum[i];
    for(int j=1;(1<r) return 0;
    int k=0;
    while((1<<(k+1))<=r-l+1) k++;
    return max(d[l][k],d[r-(1<>n&&n){
        memset(sum,0,sizeof(sum));
        int cnt=0;
        cin>>q;
        arr[0]=inf;
        for(int i=1;i<=n;i++){
            cin>>arr[i];
            num[i]=arr[i]==arr[i-1]?cnt:++cnt;
            sum[cnt]++;
            if(arr[i]==arr[i-1]) lef[i]=lef[i-1];
            else lef[i]=i;
        }
        righ[n]=n;
        for(int i=n-1;i>0;i--){
            if(arr[i]==arr[i+1]) righ[i]=righ[i+1];
            else righ[i]=i;
        }
        init_RMQ(cnt);
        int l,r;
        while(q--)
        {
            cin>>l>>r;
            int ans;
            if(num[l]==num[r]) ans=r-l+1;
            else{
                int x=righ[l]-l+1;
                int y=r-lef[r]+1;
                int z=query_RMQ(num[l]+1,num[r]-1);
                ans=max(max(x,y),z);
            }
            cout<

 

你可能感兴趣的:(线段树,RMQ)