ACM: 线段树 poj 3368
2016-05-19 23:24
495 查看
Frequent values
Description
You are given a sequence of n integers
a1 , a2 , ... ,
an in non-decreasing order. In addition to
that, you are given several queries consisting of indices
i and j (1 ≤ i ≤ j ≤ n).
For each query, determine the most frequent value among the
integers ai , ... , aj.
Input
The input consists of several test cases. Each test case starts
with a line containing two integers n and
q (1 ≤ n, q ≤ 100000). The next line
contains n integers a1 , ... ,
an (-100000 ≤ ai ≤ 100000,
for each i ∈ {1, ..., n}) separated by spaces. You can
assume that for each i ∈ {1, ..., n-1}: ai ≤
ai+1. The following q lines contain
one query each, consisting of two integers i and
j (1 ≤ i ≤ j ≤ n), which indicate the
boundary indices for the
query.
The last test case is followed by a line containing a single
0.
Output
For each query, print one line with one integer: The number of
occurrences of the most frequent value within the given range.
Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
Sample Output
1
4
3
题意: 给定一个长度为n的序列, 有m次访问一个区间中, 出现最多的元素的次数.
解题思路:
1. 多次访问某个区间的问题, 一般用线段树来做. 题目给一段已经按照升序的序列, 需要先离散化.
线段树每个节点需要设置2个域,
num:计算在原序列中的位置, count: 当前val值得元素个数.
离散化之后建立一棵线段树,
插入元素相应的统计在每个段中的最多的元素. 用样例如图:
2.
显然, [0,3]区间的count = 4, [0,1]区间的count = 4, [2,3]区间的count = 3, ...
,以此类推
这是线段树离散化的建立,
剩下的问题就是怎么查询:
(1).其实问题可以简化为一个:
就是如果要查询原序列[5,10]时(从下标1开始), 怎么将图中(1)段
计算出2个1.
想一想可以发现, 当用二分查找的时候, 查找到相应的段时, p->left ==
p->right
记录想要查找的原序列区间[l, r]的count = (r-l+1); 这样处理在一个段中的问题了. 剩下跟一
般线段树搜索一样了.
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
struct Node
{
int count, num;//count:相应val值个数, num: 原序列序号
int val;
}p[MAX];
struct node
{
int l, r;
int count, num;
int val;
}pt[MAX*2];
int n, m;
int A, B;
inline int max(int a, int b)
{
return a > b ? a : b;
}
inline int min(int a, int b)
{
return a < b ? a : b;
}
void buildTree(int l, int r, int pos)
{
pt[pos].l = l, pt[pos].r = r;
pt[pos].count = pt[pos].num = 0;
pt[pos].val =
-(1<<30);
if(l == r) return ;
int mid = (l+r)/2;
buildTree(l, mid, pos*2);
buildTree(mid+1, r, pos*2+1);
}
void insert(Node &a, int index, int pos)
{
if(a.count > pt[pos].count)
{
pt[pos].count = a.count;
pt[pos].val = a.val;
}
if(pt[pos].l == pt[pos].r) return ;
int mid = (pt[pos].l+pt[pos].r)/2;
if(index <= mid)
insert(a, index, pos*2);
else
insert(a, index,
pos*2+1);
}
void find(int l, int r, Node &a, int pos)
{
int ll, rr;
if(pt[pos].l == 0) ll = 1;
else ll = p[ pt[pos].l-1 ].num+1;
//当前区间的第一个序号
rr = p[ pt[pos].r ].num;
if(l == ll &&
r == rr)
{
a.count = pt[pos].count;
a.val = pt[pos].val;
return ;
}
if(pt[pos].l == pt[pos].r)
{
a.count = r-l+1;
a.val = pt[pos].val;
return ;
}
Node lside, rside;
lside.count = rside.count = 0;
int mid = (pt[pos].l+pt[pos].r)/2;
if(l <= p[mid].num)
find(l, min(p[mid].num, r),
lside, pos*2);
if(r > p[mid].num)
find(max(p[mid].num+1, l), r,
rside, pos*2+1);
if(lside.count >
rside.count)
{
a.count = lside.count;
a.val = lside.val;
}
else
{
a.count = rside.count;
a.val = rside.val;
}
}
int main()
{
int i, j, t;
// freopen("input.txt","r",stdin);
while(scanf("%d",&n) !=
EOF)
{
if(n == 0) break;
else
scanf("%d",&m);
scanf("%d",&p[0].val);
p[0].num = p[0].count =
1;
j = 0;
for(i = 1; i <
n; ++i)
{
scanf("%d",&t);
if(t ==
p[j].val)
{
p[j].num++;
p[j].count++;
}
else
{
j++;
p[j].count
= 1;
p[j].num
= p[j-1].num+1;
p[j].val
= t;
}
}
n = j;
buildTree(0, n, 1);
//总共区间变成了0~n了
for(i = 0; i <=
n; ++i)
insert(p[i],
i, 1);
for(i = 0; i
< m; ++i)
{
scanf("%d
%d",&A, &B);
Node
temp;
find(A, B,
temp, 1);
printf("%d\n",
temp.count);
}
}
return 0;
}
Description
You are given a sequence of n integers
a1 , a2 , ... ,
an in non-decreasing order. In addition to
that, you are given several queries consisting of indices
i and j (1 ≤ i ≤ j ≤ n).
For each query, determine the most frequent value among the
integers ai , ... , aj.
Input
The input consists of several test cases. Each test case starts
with a line containing two integers n and
q (1 ≤ n, q ≤ 100000). The next line
contains n integers a1 , ... ,
an (-100000 ≤ ai ≤ 100000,
for each i ∈ {1, ..., n}) separated by spaces. You can
assume that for each i ∈ {1, ..., n-1}: ai ≤
ai+1. The following q lines contain
one query each, consisting of two integers i and
j (1 ≤ i ≤ j ≤ n), which indicate the
boundary indices for the
query.
The last test case is followed by a line containing a single
0.
Output
For each query, print one line with one integer: The number of
occurrences of the most frequent value within the given range.
Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
Sample Output
1
4
3
题意: 给定一个长度为n的序列, 有m次访问一个区间中, 出现最多的元素的次数.
解题思路:
1. 多次访问某个区间的问题, 一般用线段树来做. 题目给一段已经按照升序的序列, 需要先离散化.
线段树每个节点需要设置2个域,
num:计算在原序列中的位置, count: 当前val值得元素个数.
离散化之后建立一棵线段树,
插入元素相应的统计在每个段中的最多的元素. 用样例如图:
2.
显然, [0,3]区间的count = 4, [0,1]区间的count = 4, [2,3]区间的count = 3, ...
,以此类推
这是线段树离散化的建立,
剩下的问题就是怎么查询:
(1).其实问题可以简化为一个:
就是如果要查询原序列[5,10]时(从下标1开始), 怎么将图中(1)段
计算出2个1.
想一想可以发现, 当用二分查找的时候, 查找到相应的段时, p->left ==
p->right
记录想要查找的原序列区间[l, r]的count = (r-l+1); 这样处理在一个段中的问题了. 剩下跟一
般线段树搜索一样了.
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
struct Node
{
int count, num;//count:相应val值个数, num: 原序列序号
int val;
}p[MAX];
struct node
{
int l, r;
int count, num;
int val;
}pt[MAX*2];
int n, m;
int A, B;
inline int max(int a, int b)
{
return a > b ? a : b;
}
inline int min(int a, int b)
{
return a < b ? a : b;
}
void buildTree(int l, int r, int pos)
{
pt[pos].l = l, pt[pos].r = r;
pt[pos].count = pt[pos].num = 0;
pt[pos].val =
-(1<<30);
if(l == r) return ;
int mid = (l+r)/2;
buildTree(l, mid, pos*2);
buildTree(mid+1, r, pos*2+1);
}
void insert(Node &a, int index, int pos)
{
if(a.count > pt[pos].count)
{
pt[pos].count = a.count;
pt[pos].val = a.val;
}
if(pt[pos].l == pt[pos].r) return ;
int mid = (pt[pos].l+pt[pos].r)/2;
if(index <= mid)
insert(a, index, pos*2);
else
insert(a, index,
pos*2+1);
}
void find(int l, int r, Node &a, int pos)
{
int ll, rr;
if(pt[pos].l == 0) ll = 1;
else ll = p[ pt[pos].l-1 ].num+1;
//当前区间的第一个序号
rr = p[ pt[pos].r ].num;
if(l == ll &&
r == rr)
{
a.count = pt[pos].count;
a.val = pt[pos].val;
return ;
}
if(pt[pos].l == pt[pos].r)
{
a.count = r-l+1;
a.val = pt[pos].val;
return ;
}
Node lside, rside;
lside.count = rside.count = 0;
int mid = (pt[pos].l+pt[pos].r)/2;
if(l <= p[mid].num)
find(l, min(p[mid].num, r),
lside, pos*2);
if(r > p[mid].num)
find(max(p[mid].num+1, l), r,
rside, pos*2+1);
if(lside.count >
rside.count)
{
a.count = lside.count;
a.val = lside.val;
}
else
{
a.count = rside.count;
a.val = rside.val;
}
}
int main()
{
int i, j, t;
// freopen("input.txt","r",stdin);
while(scanf("%d",&n) !=
EOF)
{
if(n == 0) break;
else
scanf("%d",&m);
scanf("%d",&p[0].val);
p[0].num = p[0].count =
1;
j = 0;
for(i = 1; i <
n; ++i)
{
scanf("%d",&t);
if(t ==
p[j].val)
{
p[j].num++;
p[j].count++;
}
else
{
j++;
p[j].count
= 1;
p[j].num
= p[j-1].num+1;
p[j].val
= t;
}
}
n = j;
buildTree(0, n, 1);
//总共区间变成了0~n了
for(i = 0; i <=
n; ++i)
insert(p[i],
i, 1);
for(i = 0; i
< m; ++i)
{
scanf("%d
%d",&A, &B);
Node
temp;
find(A, B,
temp, 1);
printf("%d\n",
temp.count);
}
}
return 0;
}
相关文章推荐
- ACM: 线段树 poj 3264
- ACM: 树状数组 poj 3321 图论+树状…
- ACM: 树状数组 poj 2155 学习《浅…
- ACM: 树状数组 poj 1195
- ACM: 线段树 poj 2482 煽情的情书!…
- C++ 友元类
- ACM: 线段树 poj 3277
- ACM: 线段树 poj 3468
- ACM: 线段树 poj 2886 约瑟夫问题
- ACM: 线段树 poj 2777 继续熟练线…
- 协同开发时, 如何合并不稳定的联调代码?
- ACM: 线段树 poj 2828 认真对待每…
- ACM: trie树 poj 2513
- 计算机和资料 转载
- 凌宇的项目之旅-关于自定义锁屏
- Jmeter文章索引贴
- codeforces 675C C. Money Transfers(贪心)
- ACM: 线段树 poj 1177
- ACM: 线段树 poj 1151 足足想了三…
- ACM: 线段树 poj 2352