[POJ3368][UVA11235] Frequent values[ST表]

本文介绍了一种处理不降序列区间查询问题的算法,通过预处理构建ST表,实现快速查询区间内出现次数最多的数的出现次数。利用RMQ算法优化查询效率,适用于多组数据的快速处理。

题意:给出一个不降序列,有多个询问,询问[l,r]中出现次数最多的数的出现次数

多组数据

对于序列-1 -1 1 1 1 1 3 10 10 10

可以这么理解<-1,2>, <1, 4>, <3,1>, <10,3>
cnt[i]记录这个数字的出现次数,lef[i]记录左端点,righ[i]记录右端点,belong[i]代表第i个数字属于哪一块
把块和数量丢进st表
然后对于区间[l,r],答案就是 \(min(r, righ[l])-l+1\)\(r-max(l, lef[r])+1\)\(RMQ(belong[l]+1,belong[r]-1)\)中最大的一个
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

const int inf = 0x3f3f3f3f;
inline void chmax(int &x, int y) {if (x < y) x = y;}
inline void chmin(int &x, int y) {if (x > y) x = y;}
const int MAXN = 1e5+7;
int n, m, st[21][MAXN], a[MAXN], len[MAXN], belong[MAXN], lef[MAXN], righ[MAXN], tot, cnt[MAXN], Pow[21], logg[MAXN];
inline int read() {
    int c = getchar(), f = 1, x = 0;
    while(!isdigit(c)) (c=='-')&&(f=-f), c = getchar();
    while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
    return x * f;
}
inline int RMQ(int l, int r) {
    int k = logg[r-l+1];
    return max(st[k][l], st[k][r-Pow[k]+1]);
}
int main(void) {
    for(int i = 2; i <= 100000; ++i) logg[i] = logg[i>>1] + 1;
    for(int i = 0; i <= 20; ++i) Pow[i] = (1<<i);
    while((n = read())) {
        tot = 0; memset(cnt, 0, n*4);
        m = read();
        for(int i = 1; i <= n; ++i) a[i] = read();  
        for(int i = 1; i <= n; ++i) {
            if (a[i] != a[i-1]) lef[i] = i, belong[i] = ++tot;
            else lef[i] = lef[i-1], belong[i] = tot;
            ++cnt[tot];
        }
        for(int i = n; i >= 1; --i) {
            if (a[i] != a[i+1]) righ[i] = i;
            else righ[i] = righ[i+1];
        }
        for(int i = 1; i <= tot; ++i) st[0][i] = cnt[i];
//      for(int i = 1; i <= n; ++i) cout << lef[i] << " \n"[i==n];
//      for(int i = 1; i <= n; ++i) cout << righ[i]<< " \n"[i==n];
//      for(int i = 1; i <= n; ++i) cout << belong[i]<<" \n"[i==n];
//      for(int i = 1; i <= tot; ++i) cout << cnt[i] << " \n"[i==n];
        int mm = logg[n];
        for(int i = 1; i <= mm; ++i)
            for(int j = 1; j <= tot; ++j)
                st[i][j] = max(st[i-1][j], st[i-1][j+Pow[i-1]]);
        while(m--) {
            int l = read(), r = read();
            if (belong[l] == belong[r]) printf("%d\n", r-l+1);
            else {
                int ans = min(r, righ[l]) - l + 1;
                chmax(ans, r - max(l, lef[r]) + 1);
                if (belong[l] + 1 <= belong[r] - 1) chmax(ans, RMQ(belong[l]+1, belong[r] - 1));
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/storz/p/10191551.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值