Frequent Values-线段树求解出现最多的数
Frequent Values(poj 3368)
注意:以下答案为离线作答结果,并非能通过poj,若要通过poj,需要修改函数接口,因为以下程序接受半封闭区间(s,e],同时还需要修改输入数据的顺序
求出现最多的数:
给定n个数,已按从大到小顺序排列好,一共有q个询问,每次询问一个区间,问这个区间中出现次数最多的数是什么。
题目数据范围:
数的个数,1 ≤ n ≤ 100000
询问次数,1 ≤ q ≤ 100000
每个数的大小,-100000 ≤ ai ≤ 100000
思路:
使用线段树解决。因个数比较多,最多有10w个数据,又因为输入是有序的,从大到小输入。因此可以将相同数据保存到同一个结构体中,并记录一共有多少个相同的元素。这样做既可以免去合并子树求解出现最多数的麻烦,也节约了空间,提高了效率。
题目中使用数组来模拟线段树。
/**********************************************************
作者:SunboyL
题目3:Frequent Values(poj 3368) 求出现最多的数:
给定n个数,已按从大到小顺序排列好,一共有q个询问,每次询问一个区间,问这个区间中出现次数最多的数是什么。
题目数据范围:
数的个数,1 ≤ n ≤ 100000
询问次数,1 ≤ q ≤ 100000
每个数的大小,-100000 ≤ ai ≤ 100000 思路:很容易想到建立线段树,并在线段树的每个结点中保存区间中出现次数最多的数。
需要解决的问题,两个子结点的信息如何合并到父结点。
很显然,子结点中出现次数最多的数不一定就是父结点中出现次数最多的数 时间:2013.10.28
**********************************************************/ #include <vector>
#include <algorithm>
#define MAXN (100000) typedef struct _dataSet
{// 一个值相同的数据集合
int value,count,lastNumSeq; //value表示一个值;count表示有多少个value值,seq表示在线性表中该集合最后一个值的序号
int setSeq;// 集合序号,表示第几个集合
}DataSet; typedef struct _segTree
{
int s,e; // 表示区段[s,e)
DataSet mostValue; // mostValue表示区段[s,e)中出现最多的值.
}SegTree,*pSegTree; void buildSegTree(pSegTree tree,int start,int end,int node)
{ // tree为树根节点,start到end区间为[start,end),node表示节点编号
tree[node].s = start;
tree[node].e = end;
tree[node].mostValue.value = 0x80000000;//0x80000000为最小的32位整数
if(start + == end)
return;
int mid = (start + end) >> ;
buildSegTree(tree,start,mid,node*); // 建立左子树
buildSegTree(tree,mid,end,node*+); // 建立右子树
} void insertDataSet(pSegTree segTree,const DataSet& dataSet,int node = )
{// 将dataSet插入到segTree中,node默认指向根节点,调用时忽略此参数
if(dataSet.count > segTree[node].mostValue.count)
segTree[node].mostValue = dataSet;// 每个节点都记录区间中出现次数最多的数
if(segTree[node].s + == segTree[node].e)
return;// 叶子节点
int mid = (segTree[node].s + segTree[node].e) / ;
if(dataSet.setSeq < mid) // 线段树以集合的个数来划分线段,因此使用集合所在的序号判断插入到左子树或是右子树
insertDataSet(segTree,dataSet,node*);
else
insertDataSet(segTree,dataSet,node*+);
} DataSet query(pSegTree tree,const std::vector<DataSet>& dataSet,int l,int r,int node = )
{// 查询在线性列表dataSet[]中(l,r]区间出现次数最多的数,并返回该数的相同元素集合
DataSet result;
int mid = (tree[node].s + tree[node].e) / ;
int ds,de; // 将以集合为单位的区间转换为以单个数据值为单位的区间[ds,de)
if(tree[node].s == )
ds = ;
else
ds = dataSet[tree[node].s - ].lastNumSeq + ;
de = dataSet[tree[node].e - ].lastNumSeq + ; // 因为std::vector<DataSet>& dataSet数组从0开始,所以相对起始位置,应该是减2 if(l == ds && r == de)
{
return tree[node].mostValue;
}
if(tree[node].s + == tree[node].e)
{
result = tree[node].mostValue;
result.count = r - l;// 区间并不完全覆盖相同元素的集合,则相同的个数为其部分覆盖的个数。
return result;
}
DataSet a,b;
a.count = b.count = ;
if(l <= dataSet[mid - ].lastNumSeq)
a = query(tree,dataSet,l,std::min(r,dataSet[mid - ].lastNumSeq + ),node*);
if(r > dataSet[mid - ].lastNumSeq + )
b = query(tree,dataSet,std::max(l,dataSet[mid - ].lastNumSeq + ),r,node*+);
result = a.count>b.count?a:b;
return result;
} void frequentValues()
{// frequentValues函数是本程序接口。负责输入。
int n,i; // n:有多少个要输入的元素
std::vector<DataSet> dataSet; // 本题目主要研究线段树而非线性表,这里就使用一下容器偷懒
DataSet temp; std::cin >> n; // 输入一共有多少个数据
if(n < || n > MAXN) // 元素个数为1到100000
return; std::cin >> temp.value;// 输入第一个元素的值
temp.count = ;
temp.lastNumSeq = ;
temp.setSeq = ;// 第一个集合
dataSet.push_back(temp);
int q = ; // 指向dataSet数组中当前值(集合)的指针 for( i = ;i <= n;++i )
{
std::cin >> temp.value;
if(temp.value == dataSet[q].value)
{
dataSet[q].count ++;
dataSet[q].lastNumSeq ++;
}
else
{
temp.count = ; // 值不相同,表示另外一个集合,充值value值有一个,序号为前一个集合的最后一个值的序号加一
temp.lastNumSeq = dataSet[q].lastNumSeq + ;
temp.setSeq = dataSet[q++].setSeq + ;
dataSet.push_back(temp);
}
}
int size = dataSet.size(); // 记录值不同的集合有多少个,并利用这个,建立1-size的线段树
pSegTree segTree = new SegTree[*size]; buildSegTree(segTree,,size+,); // 以segTree为根节点,集合个数size(1-size+1)为线段区间建立线段树
for(i = ;i < size;++i)
insertDataSet(segTree,dataSet[i]);// 将dataSet中的数据集合插入到线段树中 int ask; // 多少次询问
std::cin >> ask;
while(ask --)
{
DataSet result;
int l,r;
std::cin >> l >> r;// 输入要询问的区间[l,r)
result = query(segTree,dataSet,l,r);
int t = result.value;
std::cout << t << std::endl;
}
delete[] segTree; } #include <iostream>
#include <list>
using namespace std;
int main()
{
//MergeSortTest(); // 测试题目一,归并排序
//movableWindowsTest();// 测试题目二,移动窗口,输出窗口中的最小值
//MonkeyKingTest();// 测试题目三,猴王monkey king
frequentValues(); // 测试题目四,Frequently Values return ;
}
20
50 48 48 48 48 47 39 39 39 39 20 20 17 16 16 16 16 16 12 11
5
1 21
3 12
5 9
7 17
7 18
输出结果如下:
Frequent Values-线段树求解出现最多的数的更多相关文章
- POJ 3368 Frequent values 线段树与RMQ解法
题意:给出n个数的非递减序列,进行q次查询.每次查询给出两个数a,b,求出第a个数到第b个数之间数字的最大频数. 如序列:-1 -1 1 1 1 1 2 2 3 第2个数到第5个数之间出现次数最多的是 ...
- UVA 11235 Frequent values 线段树/RMQ
vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...
- POJ3368(Frequent values)--线段树
题目在这里 3368 Accepted 7312K 1829MS C++ 6936B 题意为给你一组数据,再给定一组区间,问你这个区间内出现次数最多的元素的次数是多少. 我还记得这题是学校校赛基础的题 ...
- HDOJ-1806 ( Frequent values ) 线段树区间合并
http://acm.hdu.edu.cn/showproblem.php?pid=1806 线段树维护区间出现频率最高的出现次数.为了维护上者,需要维护线段前后缀的出现次数,当和其他线段在端点处的字 ...
- hdu 1806 Frequent values 线段树
题目链接 给一个非递减数列, n个数, m个询问, 每个询问给出区间[L, R], 求这个区间里面出现次数最多的数的次数. 非递减数列, 这是最关键的一个条件... 需要保存一个区间最左边的数, 最右 ...
- 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)
Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...
- CodeChef - ANDMIN —— 线段树 (结点最多被修改的次数)
题目链接:https://vjudge.net/problem/CodeChef-ANDMIN Read problems statements in Mandarin Chinese, Russia ...
- hdu 4983 线段树+斐波那契数
http://acm.hdu.edu.cn/showproblem.php?pid=4893 三种操作: 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 从l到r区间 ...
- HYSBZ - 2243 树链剖分 + 线段树 处理树上颜色段数
用线段树处理颜色段数 记录区间内的颜色段数,区间右端点的颜色,区间右端点的颜色. int tr[maxn<<2], lc[maxn<<2], rc[maxn<<2] ...
随机推荐
- 如何使用Photoshop(PS)将图片的底色变为透明
很多时候需要将一张图片的底色变得透明.本文描述了使用PS将图片的一部分变得透明的方法.本例将一段艺术字的背景去掉,将背景透明的文字单独保存成图片,这样以后将这段文字粘贴到其他素材上的时候,就不用担心它 ...
- java代理模式及动态代理类
1. 代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 ...
- extjs经典的增删改查
首先,编辑一下yepnope,生成yepnope.jsp,如下: <%@ page language="java" pageEncoding="UTF-8" ...
- redis 优缺点 使用场景
1. 使用redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,li ...
- windows7 mongodb 安装急遇到的问题
偶尔上一次博客园,才发现自己这么久没有写东西了.今天更新一篇. 作为前端开发者,node.js 无非是一个强心剂.有了node.js 后端开发变得不需要再搞另一门语言,一个javascript 就能搞 ...
- Java动态代理机制小结
因为最近学习hadoop中用到了动态代理的相关知识,之前AOP编程也碰到过,所以在这里特地总结一下. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(In ...
- nginx-1.14.0安装
1.百度搜索Nginx,点击Nginx news官网,点击nginx-1.13.10进入下载网页,选择Stable version的版本之后下载. 2.进入根目录,cd / 3.在根目录下创建soft ...
- JVM源码分析之Metaspace解密
概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所 ...
- 拖拽 支持ie6
可随意拖拽方块至任一位置: 1.setCapture方法:多用于容器对象,效果是对指定的对象设置鼠标捕获.使在容器内的子对象的鼠标事件均由容器对象触发,因此,只能在容器对象的鼠标事件函数中进行处理.当 ...
- JQ 时间插件
<script type="text/javascript" charset="utf-8" src="__PUBLIC__/ueditor/u ...