poj 1806 Frequent values(RMQ 统计次数) 详细讲解
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1806
题目大意:给你一个非降序排列的整数数组,你的任务是对于一系列的询问,(i,j),回答序列中出现次数最多的数的个数;
如下图所示:
AC代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
#include<cmath>
using namespace std;
const int N = 1e5+;
int a[N],b[N];
int dp[N][];
int n,m;
//构造和寻找的代码,来自大白书
void buildrmq( )
{
for(int i=;i<n;i++)
dp[i][]=b[i];
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<n;i++)
dp[i][j]=max(dp[i][j-],dp[i+(<<(j-))][j-]);
}
int search(int s,int v)
{
int k = ;
while(<<(k+) <= v-s+) k++;
return max(dp[s][k],dp[v-(<<k)+][k]);
}
int bi_search(int s,int t)
{
int tmp=a[t];
int l=s;
int r=t;
int mid;
while(l<r)
{
mid=((l+r)>>);
if(a[mid]>=tmp) r=mid;
else l=mid+;
}
return r;
}
int main()
{
int T;
while(scanf("%d",&n) && n)
{
memset(b,,sizeof(b));
memset(dp,,sizeof(dp));
scanf("%d",&m);
for(int i =; i<n; i++)
scanf("%d",&a[i]);
a[n] = a[n-]+;
for(int i =n-; i>=; i--)//倒序统计单个数在当前段出现的次数
{
if(a[i] == a[i+])
{
b[i] = b[i+]+;
}
else b[i] =;
}
buildrmq( );//构造RMQ函数
int L,R,ans;
for(int i=; i<=m; i++)
{
scanf("%d %d",&L,&R);
L = L-;R = R-;//题目中是从1开始计数的;
int temp = bi_search(L,R);//寻找数组中最左端等于a[R]的数
ans = b[temp] - b[R]+; //统计和最左边相同的数出现的次数
if(L == temp) printf("%d\n",ans);//如果这一区间中的数字相同的话,直接左边减去右边
else printf("%d\n",max(ans,search(L,temp-)));//否则,寻找(L,temp)中的最大数,进行比较
}
}
return ;
}
AC代码2:线段树
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e5+;
int a[N];
int ans ;
struct node
{
int L,R,count,fre;
int lcount,lfre;
int rcount,rfre;
}tree[*N];
/*
l,r存该节点的边界。
count存该节点中出现最多的数字的个数,fre存该节点中出现最多的数字。
lcount 存该节点左端连续出现的数字的个数, lfre存该节点左端连续出现的数字。
rcount 存该节点右端连续出现的数字的个数, rfre存该节点右端连续出现的数字。
*/
void build(int l,int r,int v)
{
tree[v].L = l;
tree[v].R = r;
if(l == r)
{
tree[v].fre = tree[v]. rfre = tree[v].lfre = a[r];
tree[v].count = tree[v].lcount = tree[v].rcount = ;
return ;
}
int mid = (l+r)/;
build(l,mid,v*);
build(mid+,r,v*+);
int tmpc,tmpf;
if(tree[v*].count>tree[v*+].count)
{
tree[v].count = tree[v*].count;
tree[v].fre = tree[v*].fre;
}
else
{
tree[v].count = tree[v*+].count;
tree[v].fre = tree[v*+].fre;
}
tree[v].lcount = tree[v*].lcount;
tree[v].rcount = tree[v*+].rcount;
if(tree[v*].rfre == tree[v*+].lfre)
{
tmpc = tree[v*].rcount +tree[v*+].lcount;
tmpf = tree[v*].rfre;
if(tree[v].count<tmpc)
{
tree[v].count = tmpc;
tree[v].fre = tmpf;
}
if(tree[v*].lfre == tree[v*+].lfre)
tree[v].lcount = tree[v].lcount+tree[v*+].lcount;
if(tree[v*].rfre == tree[v*+].rfre)
tree[v].rcount= tree[v*].rcount+tree[v].rcount;
}
tree[v].lfre = tree[v*].lfre;
tree[v].rfre = tree[v*+].rfre;
}
void update(int x,int y,int v)
{
int mid,s1,s2;
if(tree[v].L == x && tree[v].R == y)
{
if(tree[v].count>ans)
ans = tree[v].count;
return ;
}
mid = (tree[v].L+tree[v].R)/;
if(y<=mid) update(x,y,v*);
else if(x>mid) update(x,y,v*+);
else {
update(x,mid,v*);
update(mid+,y,v*+);
if(tree[v*].rfre == tree[v*+].lfre)
{
if(a[x] != tree[v*].rfre) s1 = tree[v*].rcount;
else s1 = mid-x+;
if(a[y]!=tree[v*+].lfre) s2 = tree[v*+].lcount;
else s2 = y - mid;
if(s1+s2>ans) ans = s1+s2;
}
}
}
int main()
{
int m,n,x,y;
while(scanf("%d",&m) && m)
{
scanf("%d\n",&n);
for(int i=;i<=m;i++)
scanf("%d",&a[i]);
build(,m,);
for(int i=;i<=n; i++)
{ ans = ;
scanf("%d %d",&x,&y);
if(x==y) {printf("1\n");continue;}
update(x,y,);
printf("%d\n",ans);
}
}
return ;
}
poj 1806 Frequent values(RMQ 统计次数) 详细讲解的更多相关文章
- poj 3368 Frequent values(RMQ)
/************************************************************ 题目: Frequent values(poj 3368) 链接: http ...
- POJ 3368 Frequent values RMQ ST算法/线段树
Frequent values Time Limit: 2000MS Memory Lim ...
- POJ 3368 Frequent values(RMQ 求区间出现最多次数的数字的次数)
题目链接:http://poj.org/problem? id=3368 Description You are given a sequence of n integers a1 , a2 , .. ...
- POJ 3368 Frequent values RMQ 训练指南 好题
#include<cstdio> #include<cstring> ; const int inf=0x3f3f3f3f; inline int max(int x,int ...
- RMQ算法 以及UVA 11235 Frequent Values(RMQ)
RMQ算法 简单来说,RMQ算法是给定一组数据,求取区间[l,r]内的最大或最小值. 例如一组任意数据 5 6 8 1 3 11 45 78 59 66 4,求取区间(1,8) 内的最大值.数据量小 ...
- POJ 3368 Frequent values (基础RMQ)
Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14742 Accepted: 5354 ...
- POJ 3368 Frequent values 【ST表RMQ 维护区间频率最大值】
传送门:http://poj.org/problem?id=3368 Frequent values Time Limit: 2000MS Memory Limit: 65536K Total S ...
- [HDU 1806] Frequent values
Frequent values Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- poj 3368 Frequent values(段树)
Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13516 Accepted: 4971 ...
随机推荐
- 如何优雅的编写Objective-C语言?
① 减少缩写 命名缩写只用于通用专业术语,如URL,不可自创命名缩写,如Ctr.Msg.命名宁可长一些,也不要难于理解. ② 过程化 动作发生之前用Will,发生之后用Did,询问是否发生用Shoul ...
- nano命令,vi ed pico sed joe emacs jed ex
nano命令 nano是一个字符终端的文本编辑器,有点像DOS下的editor程序.它比vi/vim要简单得多,比较适合Linux初学者使用.某些Linux发行版的默认编辑器就是nano. nan ...
- python利用opencv去除水印方法
OpenCV(Open Source Computer Vision Library)是一个跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法 在python中可以利用opencv来去除 ...
- 《深入理解Java虚拟机》笔记6
class文件由无符号数和表两种类型数据构成.表其实相当于一种结构体,内部又嵌套无符号数或者表. 用u1,u2,u4,u8分别代表一个字节,两个字节,四个字节,八个字节的无符号数. 如图中所示,cla ...
- web页面实时更新页面的原理--WebSocket
原文:https://www.jianshu.com/p/8f956cd4d42b angular-cli启动的项目也可以自动刷新,底下应该也是应用的websocket的原理. ----------- ...
- 手写Json转换
在做项目的时候总是要手动将集合转换成json每次都很麻烦,于是就尝试着写了一个公用的方法,用于转换List to json: using System; using System.Collection ...
- Java中内存泄露及垃圾回收机制
转自:http://blog.sina.com.cn/s/blog_538b279a0100098d.html 写的相当不错滴...................... 摘 要 Java语言中,内 ...
- Linux命令之编辑
vi是终端命令行里功能最强的文本编辑器了,但眼下须要用到的仅仅是文本编辑功能.与GCC.make等工具的整合应用如今还不须要,所以操作难度不大,习惯就好. Linux发行版所带的一般不是vi,而是vi ...
- Android fragment 切换载入数据卡顿问题
接着上一篇项目的进度.上一篇讲了怎样利用fragment来实现下拉菜单.公用菜单,以实现切换主界面数据的功能,这时候遇到的问题是:使用了fragment的切换界面方法.但载入的数据太多.用户从一个界面 ...
- Spring官方下载地址
改版后的Spring官方网站下载地址找不到了,汗~~ 可以通过该链接下载对应的包:http://repo.spring.io/milestone/org/springframework/ Spring ...