zoukankan      html  css  js  c++  java
  • CSU-2221 假装是区间众数(ST表模版题)

    题目链接

    题目

    Description

    给定一个非递减数列Ai,你只需要支持一个操作:求一段区间内出现最多的数字的出现次数。

    Input

    第一行两个整数N,Q

    接下来一行有N个整数,表示这个序列。

    接下来Q行每行一个操作:A B,询问A到B之间出现最多的数字。

    1<=N,Q<=100000。-100000<=Ai<=100000

    Output

    每组数据若干行,每行对应一个询问的答案。

    Sample Input

    10 3
    -1 -1 1 1 1 1 3 10 10 10
    2 3
    1 10
    5 10
    

    Sample Output

    1
    4
    3
    

    题解

    这个题是ST表+RMQ模版题

    首先题中所给序列是非递减序列,所有相等的数都会聚在一块,所以我们可以将相等的数字划为一段,(value[i]和cnt[i])分别表示第i段对应的数值和出现的次数,(num[p],L[p],R[p])分别表示位置p所在段的编号和左右端点的位置,每次查询(l, r)的结果分为三部分的最大值,从(l到l)所在段的右端点的元素个数((R[l]-l+1)),从r所在段的左端点到r的元素个数((r-L[r]+1)),中间第(num[l]+1段到num[r]-1)段cnt的最大值,这样就可以用rmq解决了。

    顺便复习一下ST+RMQ

    时间复杂度:预处理(o(nlogn)),查询(o(1))

    (st[i][j])表示从i开始,长度为(2^j)的一段元素中的最小(大)值,则可以用递推的方式计算(st[i][j])

    [st[i][j]=min(st[i][j-1],st[i+2^{j-1}][j-1]) ]

    循环的时候注意先枚举区间长度,即先枚举j,再枚举起点i,从小区间到大区间。

    查询也很简单,查询(L,R)区间内的最小(大)值,直接令x为满足(2^x le R-L+1)的最大整数,则以L开头,R结尾的两个长度为(2^x)的区间覆盖了(L,R),由于是取最小值,所以有些元素考虑多遍也没关系,故ST表不能用于区间和

    AC代码

    #include<bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    
    int a[maxn];
    int value[maxn], cnt[maxn], num[maxn], L[maxn], R[maxn];
    int st[maxn][20], lg2[maxn];
    int n, q;
    int k;
    
    void ST() {
        for (int i = 1; i <= k; i++) {
            st[i][0] = cnt[i];
        }
        for (int j = 1; (1 << j) <= k; j++) {
            for (int i = 1; (i + (1 << j) - 1) <= k; i++) {
                st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
            }
        }
        for (int i = 2; i <= k; i++) {
            lg2[i] = lg2[i >> 1] + 1;
        }
    }
    
    int rmq(int l, int r) {
        if (l>r)
            return 0;
        else {
            int x = lg2[r - l + 1];
            return max(st[l][x], st[r - (1 << x) + 1][x]);
        }
    }
    
    int main() {
        scanf("%d%d", &n, &q);
        k = 0;
        value[0] = 0x3f3f3f3f;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            if (a[i] != value[k]) {
                R[k] = i;
                value[++k] = a[i];
                L[k] = i - 1;
                cnt[k] = 1;
                num[i] = k;
            }
            else {
                cnt[k]++;
                num[i] = num[i - 1];
            }
        }
        R[k] = n + 1;
        ST();
        while (q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            if (num[l] == num[r]) {
                printf("%d
    ", r - l + 1);
            }
            else {
                int tmp = max(R[num[l]] - l, r - L[num[r]]);
                int ans = max(tmp, rmq(num[l] + 1, num[r] - 1));
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    
    /**********************************************************************
        Problem: 2221
        User: Artoriax
        Language: C++
        Result: AC
        Time:128 ms
        Memory:12572 kb
    **********************************************************************/
    
  • 相关阅读:
    20200318
    20200317
    Thinkphp 操作多个数据库
    base格式图片转文件存储
    Thinkphp POST 和 GET 传值
    Thinkphp调用微信扫一扫实例,学会再也不怕客户在微信提的奇葩要求了
    centos 安装ngnix mysql php
    PHP 区分微信、支付宝、QQ扫码
    PHP秒数计算时分秒
    Thinkphp 获取访问者的ip
  • 原文地址:https://www.cnblogs.com/artoriax/p/10370607.html
Copyright © 2011-2022 走看看