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-线段树求解出现最多的数的更多相关文章

  1. POJ 3368 Frequent values 线段树与RMQ解法

    题意:给出n个数的非递减序列,进行q次查询.每次查询给出两个数a,b,求出第a个数到第b个数之间数字的最大频数. 如序列:-1 -1 1 1 1 1 2 2 3 第2个数到第5个数之间出现次数最多的是 ...

  2. UVA 11235 Frequent values 线段树/RMQ

    vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...

  3. POJ3368(Frequent values)--线段树

    题目在这里 3368 Accepted 7312K 1829MS C++ 6936B 题意为给你一组数据,再给定一组区间,问你这个区间内出现次数最多的元素的次数是多少. 我还记得这题是学校校赛基础的题 ...

  4. HDOJ-1806 ( Frequent values ) 线段树区间合并

    http://acm.hdu.edu.cn/showproblem.php?pid=1806 线段树维护区间出现频率最高的出现次数.为了维护上者,需要维护线段前后缀的出现次数,当和其他线段在端点处的字 ...

  5. hdu 1806 Frequent values 线段树

    题目链接 给一个非递减数列, n个数, m个询问, 每个询问给出区间[L, R], 求这个区间里面出现次数最多的数的次数. 非递减数列, 这是最关键的一个条件... 需要保存一个区间最左边的数, 最右 ...

  6. 计蒜客 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 ...

  7. CodeChef - ANDMIN —— 线段树 (结点最多被修改的次数)

    题目链接:https://vjudge.net/problem/CodeChef-ANDMIN Read problems statements in Mandarin Chinese, Russia ...

  8. 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区间 ...

  9. HYSBZ - 2243 树链剖分 + 线段树 处理树上颜色段数

    用线段树处理颜色段数 记录区间内的颜色段数,区间右端点的颜色,区间右端点的颜色. int tr[maxn<<2], lc[maxn<<2], rc[maxn<<2] ...

随机推荐

  1. migrate的使用

    安装完yii2后,需要创建一张user表,这里用migrate创建 1.在dos窗口下,先cd到项目的目录,比如E:\>cd E:\Visual-AMP-x64\www\blog\blog 2. ...

  2. hdu Distant Galaxy(遥远的银河)

    Distant Galaxy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  3. [python小记]使用lxml修改xml文件,并遍历目录

    这次的目的是遍历目录,把目标文件及相应的目录信息更新到xml文件中.在经过痛苦的摸索之后,从python自带的ElementTree投奔向了lxml.而弃用自带的ElementTree的原因就是,na ...

  4. ORACLE中关于 char 和 varchar2 的比较

    先建表做一个测试: ) , VARC2 )), CHAR2 ) ; INSERT INTO TT VALUES('A','A','A') ; INSERT INTO TT VALUES('A','A ...

  5. poj3253 优先队列

    Farmer John wants to repair a small length of the fence around the pasture. He measures the fence an ...

  6. PHP学习笔记(14)班级和学生管理---学生

    两个文件夹,一个班级cls,一个学生stu. 两个表,一个班级cls,一个学生stu. 每个文件夹里有7个php文件:主界面stu.php-------增add.php,insert.php----- ...

  7. php安装redis扩展初始化失败解决办法

    错误信息如下: PHP Warning: PHP Startup: redis: Unable to initialize module Module compiled with module API ...

  8. City Destruction Kattis - city dp

    /** 题目:City Destruction Kattis - city 链接:https://vjudge.net/problem/Kattis-city 题意:有n个怪兽,排成一行.每个怪兽有一 ...

  9. 2016-2017 ACM-ICPC CHINA-Final H Great Cells ans[i]*i看做整体,转化为期望理解来解题

    /** 题目:2016-2017 ACM-ICPC CHINA-Final H Great Cells 链接:http://codeforces.com/gym/101194 题意:给定n*m的矩形, ...

  10. oracle 存储过程中使用date 时、分、秒丢失

    今天有一开发兄弟找我.说出现一奇怪现象,在存储过程中赋date类型的值,时.分.秒都丢失了,以下来做个试验: SQL> drop table test purge; SQL> create ...