POJ 3368 Frequent values 线段树与RMQ解法
题意:给出n个数的非递减序列,进行q次查询。每次查询给出两个数a,b,求出第a个数到第b个数之间数字的最大频数。
如序列:-1 -1 1 1 1 1 2 2 3
第2个数到第5个数之间出现次数最多的是数字1,它的频数3。
思路:假设查询时的参数为a, b。这道题查询时有以下两种情况:
1、 num[a] = num[b]. 即区间内的数字全相同,此时答案为b - a + 1。
2、 如果不相同,则以一般情况来讨论。见下图。
因为序列为非递减序列,因此值相同的数字必然连续出现。将区间分为3部分。num[a]以及与它值相同的区域构成第一部分,num[b]以及与它值相同的区域构成第三部分。区间[a, b]中剩下的构成第二部分。
定义left[i]表示与num[i]值相等的数字从左起开始的下标,right[i]表示与num[i]值相等的数字从右起开始的下标。
由图易知,第二部分里的数字,left与right值均在区间[a,b]内。
当给出区间范围a,b后,第一部分在区间内出现的次数为right[a] - a + 1。第三部分在区间内出现的次数为b - left[b] + 1。
如果right[a] + 1 > left[b] - 1,说明区间没有第二部分,直接输出上面两个值中的较大者。
如果存在第二部分,需要求出第二部分里的最大频数。不过这次就非常好求了,因为所有的数开始和结束都是在第二部分中,不存在部分出现的情况。定义tmax[i] = right[i] - left[i] + 1。则第二部分里数字的最大出现次数,即为该区间内tmax的最大值。将该值求出后与前面一三部分求出的较大者比较,最大的值即为最终答案。
因为查询量巨大,当第二部分需要计算时,可以采用线段树或者rmq。
现将两种方法的代码都给出。根据提交的结果来看,线段树所需空间远小于rmq,且速度稍快一点(不排除服务器的偶然性以及我rmq代码的效率比较低等原因)。
线段树求解代码
#include<stdio.h>
#include<algorithm>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define maxn 100020
#define inf 0x3f3f3f3f
using namespace std; int num[maxn], left[maxn], right[maxn], tmax[maxn<<];
void PushUp(int rt)
{
tmax[rt] = max(tmax[rt<<], tmax[rt<<|]);
}
void build(int l,int r,int rt)
{
if (l == r)
{
tmax[rt] = right[l] - left[l] + ;
return;
}
int m = (l + r) >> ;
build(lson);
build(rson);
PushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R) return tmax[rt];
int m = (l + r) >> ;
int ret = -inf;
if (L <= m) ret = max(ret, query(L, R, lson));
if (m < R) ret = max(ret, query(L, R, rson));
return ret;
}
int main()
{
int n, q;
//freopen("data.in", "r", stdin);
while (~scanf("%d",&n) && n)
{
scanf("%d",&q);
for (int i = ; i < n; i++)
{
scanf("%d",&num[i]);
if (!i || num[i] != num[i-]) left[i] = i;
else left[i] = left[i-];
}
for (int i = n - ; i > -; i--)
{
if (i == (n - ) ||num[i] != num[i+])
right[i] = i;
else right[i] = right[i+];
}
build(, n - , );
while (q--)
{
int a, b;
scanf("%d%d",&a,&b);
a--; b--;
if (num[b] == num[a]) printf("%d\n", b - a + );
else
{
int tem = max(right[a] - a + , b - left[b] + );
if (right[a] + > left[b] - ) printf("%d\n",tem);
else printf("%d\n", max(tem, query(right[a] + , left[b] - , , n - , )));
}
}
}
return ;
}
================================
rmq st算法求解代码
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define maxn 100020
using namespace std; int num[maxn], left[maxn], right[maxn], tmax[maxn][];
void st(int n)
{
int k = (int)(log((double)n) / log(2.0));
for (int i = ; i < n; i++)
tmax[i][] = right[i] - left[i] + ;//递推的初值
for (int j = ; j <= k; j++)
for (int i = ; i + ( << j) - < n; i++)
{
int m = i + ( << (j - ));//求出中间值
tmax[i][j] = max(tmax[i][j-], tmax[m][j-]);
}
}
//查询i和j之间的最值,注意i是从0开始的
int rmq(int i, int j)
{
int k = (int)(log(double(j - i + )) / log(2.0));
int t1 = max(tmax[i][k], tmax[j-(<<k)+][k]);
return t1;
}
int main()
{
int n, q;
//freopen("data.in", "r", stdin);
while (~scanf("%d",&n) && n)
{
scanf("%d",&q);
for (int i = ; i < n; i++)
{
scanf("%d",&num[i]);
if (!i || num[i] != num[i-]) left[i] = i;
else left[i] = left[i-];
}
for (int i = n - ; i > -; i--)
{
if (i == (n - ) ||num[i] != num[i+])
right[i] = i;
else right[i] = right[i+];
}
st(n);
while (q--)
{
int a, b;
scanf("%d%d",&a,&b);
a--; b--;
if (num[b] == num[a]) printf("%d\n", b - a + );
else
{
int tem = max(right[a] - a + , b - left[b] + );
if (right[a] + > left[b] - ) printf("%d\n",tem);
else printf("%d\n", max(tem, rmq(right[a] + , left[b] - )));
}
}
}
return ;
}
POJ 3368 Frequent values 线段树与RMQ解法的更多相关文章
- POJ 3368 Frequent values 【ST表RMQ 维护区间频率最大值】
传送门:http://poj.org/problem?id=3368 Frequent values Time Limit: 2000MS Memory Limit: 65536K Total S ...
- UVA 11235 Frequent values 线段树/RMQ
vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...
- POJ 3368 Frequent values RMQ ST算法/线段树
Frequent values Time Limit: 2000MS Memory Lim ...
- [RMQ] [线段树] POJ 3368 Frequent Values
一句话,多次查询区间的众数的次数 注意多组数据!!!! RMQ方法: 预处理 i 及其之前相同的数的个数 再倒着预处理出 i 到不是与 a[i] 相等的位置之前的一个位置, 查询时分成相同的一段和不同 ...
- poj 3368 Frequent values(RMQ)
/************************************************************ 题目: Frequent values(poj 3368) 链接: http ...
- POJ 3368 Frequent values (基础RMQ)
Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14742 Accepted: 5354 ...
- poj 3368 Frequent values(段树)
Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13516 Accepted: 4971 ...
- poj 3368 Frequent values -Sparse-Table
Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 16537 Accepted: 5981 Description You ...
- poj 3264 Balanced Lineup(线段树、RMQ)
题目链接: http://poj.org/problem?id=3264 思路分析: 典型的区间统计问题,要求求出某段区间中的极值,可以使用线段树求解. 在线段树结点中存储区间中的最小值与最大值:查询 ...
随机推荐
- 修改python新建文件时的模板
- 第5模块闯关CSS练习题
1.列举你知道的css选择器? 说道css选择器,大家都知道有许多种,但是真要你去掰着手指头数一数的话,你可能需要数几分钟.其实这么多选择器,完全可以分为两类: 标签选择器(*是特殊情况),可但标签, ...
- Android stadio 电脑连上手机可以识别,但是连不上Android stadio
原来是因为电脑没有装Android 手机驱动,我电脑刚装了系统. 很多驱动没有装.我有一个联想驱动管理,提示我装Android手机驱动.装完之后,就可以识别到手机了. 如果你的手机在电脑不识别,那么装 ...
- ogre3D学习基础2 -- 顶点程序与片断程序
三.顶点程序与片断程序 顶点或者片断程序定义可以被多个材质使用,唯一的前提条件是必须在引用它之前在材质的渲染通路部分中定义. 一个低级顶点程序示例如下: vertex_program myVertex ...
- 【转载】主成分分析法(PCA)
https://www.jisilu.cn/question/252942 进行维数约减(Dimensionality Reduction),目前最常用的算法是主成分分析法 (Principal Co ...
- POJ 3648 Wedding(2-SAT的模型运用+DFS | Tarjan)
Wedding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10427 Accepted: 3170 Specia ...
- jQuery初级
一.简介 定义 jQuery创始人是美国John Resig,是优秀的Javascript框架: jQuery是一个轻量级.快速简洁的javaScript库.源码戳这 jQuery对象 jQuery产 ...
- 【BJOI 2019】奥术神杖
题意 你有一个长度为 $n$ 的模板串(由 $0-9$ 这 $10$ 个数字和通配符 $.$ 组成),还有 $m$ 个匹配串(只由 $0-9$ 这 $10$ 个数字组成),每个匹配串有一个魔力值 $v ...
- 糗事百科python爬虫
# -*- coding: utf-8 -*- #coding=utf-8 import urllib import urllib2 import re import thread import ti ...
- react-router路由参数
react-router会自动为路由组件插入三个参数,但是不会主动为路由组件的子组件注入 子组件当中需要在属性当中传入 不是路由组件需要注入路由参数的话,也可以使用withRouter注入,而不是从属 ...