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

题意:给出一个不降序列,有多个询问,询问[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

时间: 2024-10-18 18:27:09

[POJ3368][UVA11235] Frequent values[ST表]的相关文章

[uva11235]Frequent values(RMQ,ST,离散化)

题目链接:https://vjudge.net/problem/UVA-11235 题意:给一串不递减数字,q次询问,每次查询[l,r]内出现次数最多的数字出现的次数. 查询分两部分:一部分是[l,r]为同一个数的区间,另一部分则是在上下界处截取一部分的情况. 首先离散化,后用l[],r[],v[]分别记录每一段相同数字的左右区间和出现次数.v可以直接由r-l+1更新得到. 第一部分更新ret后,接下来的rmq分三部分: 第一部分查询左边界截取一部分的数字的当前长度,第二部分查询右边界的,第三部

【暑假】[实用数据结构]UVa11235 Frequent values

UVa 11235 Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11241   Accepted: 4110 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several qu

uva11235(Frequent values)(HDU1806)

题目地址:Frequent values 题目大意.解题思路:  见白皮书p198. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int M=100100; 8 int a[M]; 9 int val[M],cn

UVA-11235 Frequent values (RMQ)

题目大意:在一个长度为n的不降序列中,有m次询问,每次询问(i,j)表示在区间(i,j)中找出出现次数最多的元素的出现次数. 题目分析:因为序列有序,可以将序列分段,并且记录每段的元素个数.每一个元素所属的段num(i).每一个元素所属段的左端点l(i)及右端点r(i).那么对于每次询问: ans(i,j)=max(max(r(i)-i+1,j-l(j)+1),rmq(num(i)+1,num(j)-1)). ans(i,j)=r-j+1 (如果i与j属于同一段) 代码如下: # include

Uva11235 Frequent values (RMQ)

///对于每个询问(l,r),分为两个部分,前半部分求与l之前相同的数的个数直到t,后半部分从t开始直接用RMQ求解最大值就行了. ///最后结果为max(前半部分,后半部分). # include <algorithm> # include <string.h> # include <math.h> # include <iostream> using namespace std; int f[100100];///前i个有多少个相同的数 int dp[1

UVA11235 - Frequent values(BMQ)

题目链接 题目大意:可以一串不递减的序列,然后给你一个范围L,R,要求你返回L,R出现最多次的那个值的出现次数. 解题思路:将这个序列重新编码一下,把相同的数字标记成一段,然后用num记录是哪一段,用cnt记录一下出现了多少个相同的.然后查询的时候因为可能出现从一段中的某个部分开始的情况,所以要先将头和尾处理一下,标记每一段的最左端和最右端位置.中间完整的部分用BMQ. #include <cstdio> #include <cstring> #include <vector

[UVa11235]Frequent values

题目大意:给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数. 解题思路:由于是非降序排列,所有相同的数都是连在一起的. 本题可用RMQ做,但是我不会啊. 其实这题可以直接用线段树做(什么?RMQ可以用线段树做?我还是不会啊),不过需要保存三个东西,该区间出现最多的数出现的次数,该区间最左边的数出现的次数,该区间最右边出现的次数. 为什么要保存左边和右边的出现次数呢?例如区间$[1,10]$分为区间$[1,5]$和$[6

POJ3368 Frequent values 线段树

N个数为非递减顺序,给定范围l,r,求[l,r]区间内数字出现频率最高的次数. 可以用线段树来做.先说查询,我们设节点P对应的区间为[a, b],左孩子节点为p1,右孩子节点为p2,那么 P也许不等于 max(p1 , p2),原因是如果p1中频率较低的某个数与p2中出现频率较低的某个数是同一个数,并且两者出现次数加起来大于max(p1, p2),但是,题目说N个数为非递减顺序排列,所以这个可能只会发生在p1的右端和p2的左端对应的数是同一个数,因此,我们还要处理这第三个可能. 查询的问题解决,

POJ 3368 Frequent values RMQ ST算法/线段树

                                                     Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15229   Accepted: 5550 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In