zoukankan      html  css  js  c++  java
  • UVA 11235 Frequent values (RMQ )

    题意:

    给出一个非降序的序列,你的任务是对于一系列询问(i,j),回答在这个区间内出现最多的数的次数。

    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

    思路:

    • 将数字分段,相同的为一段,用value[i]和c[i]分别表示第i段的数值和出现次数,num[p],Lefe[p],Right[p]分别表示位置p所在段的编号和左右端点位置
    • 每次查询(L,R)的结果为以下三个数的最大值:从L到L所在段的结束处的元素个数(Right[L]-L+1),从R所在段的开始处到R处的元素个数(R-Left[R]+1),中间第num[L]+1段到第num[R]-1段的c的最大值(这里可以用RMQ来算)。
    • 特殊情况:如果L和R在同一段,那么答案就是R-L+1;如果L和R是相邻段,那么答案是前两个数的较大值。
    • (代码中输入是从1开始的)

    代码:
    #include<iostream>
    #include<string.h>
    using namespace std;
    const int maxn=1e5+5;

    int a[maxn],value[maxn],c[maxn],num[maxn],Left[maxn],Right[maxn],d[maxn][20],n,q;
    void init(){
       memset(c,0,sizeof(c));
        int op=1;
        for(int i=1;i<=n;i++){
            if(i==1){
                value[op]=a[i];
                c[op]++;
                num[i]=op;
                Left[i]=i;
            }
            else {
                if(a[i]==a[i-1]){
                    c[op]++;
                    num[i]=num[i-1];
                    Left[i]=Left[i-1];
                }
                else {
                    value[++op]=a[i];
                    c[op]++;
                    num[i]=op;
                    Left[i]=i;
                    int k1=i-1,k2=a[i-1],j=i-1;
                    while(a[j]==k2&&j>=1)Right[j]=k1,j--;
                }
            }
        }
        memset(d,0,sizeof(d));
        for(int i=1;i<=op;i++)d[i][0]=c[i];
        for(int j=1;(1<<j)<=op+1;j++){
            for(int i=0;i+(1<<j)-1<=op;i++){
                d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int RMQ(int l,int r){
        int k=0;
        while((1<<(k+1))<=r-l+1)k++;
        return max(d[l][k],d[r-(1<<k)+1][k]);
    }
    int main(){
        while(cin>>n){
            if(n==0)break;
            cin>>q;
            for(int i=1;i<=n;i++)cin>>a[i];
            init();
            int l,r,sum=0;
            for(int i=0;i<q;i++){
                cin>>l>>r;
                if(num[l]==num[r])cout<<r-l+1<<endl;
                else {
                    //cout<<Right[l]<<' '<<Left[r]<<endl;
                    sum=max(Right[l]-l+1,r-Left[r]+1);
                    int x=num[l]+1,y=num[r]-1;
                    if(x>y)cout<<sum<<endl;
                    else {
                        sum=max(sum,RMQ(x,y));
                        cout<<sum<<endl;
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    云开发数据库 Firebase Firestore 零基础入门视频实战教程(7 个视频)
    在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
    2021 年写 JavaScript 代码的 17 个优化技巧
    Redis 学习笔记系列文章之 Redis 的安装与配置 (一)
    selenium webdriver 删除元素
    FFT板子
    pytest一:运行几个简单的测试用例终端显示的信息
    JS 日期取年月日
    将博客搬至CSDN
    c语言编译器
  • 原文地址:https://www.cnblogs.com/ljy08163268/p/7671392.html
Copyright © 2011-2022 走看看