POJ3368_Frequent values_

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sdz20172133/article/details/84075726

Frequent values

Time Limit: 2000MS

 

Memory Limit: 65536K

Total Submissions: 22993

 

Accepted: 8051

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

Source

Ulm Local 2007

算法分析:

转自博客:

题意:

给出一个非降序排列的整数数组a1,a2,...an,你的任务是对于一系列询问(i, j),回答ai,ai+1,...aj中出现最多次数的值所出现的次数?

分析:

我们首先要线段树的节点中维护么i各区间的最大次数。但这样就来麻烦了,如何维护呢?如果一个查询区间跨越了两个区间呢?

 

但数组本身是升序的。这表示,两个区间连接之后,最大次数改变只可能发生在两个区间交接的地方。即左区间的右端和右区间的左端一样,连接起来形成了一个比原来两区间的最大值更大的一个值

 

而进行这个连接处的判断和计算,我们只需要知道左子树的右端和它在左子树中出现的次数,右子树的左端和它在右子树中出现的次数。所以,线段树的每个节点需要维护五个值:本区间内最大次数,左端点及其次数,右端点及其次数。

 

这里有两个细节需要注意:

 

1.建树时,如果合并区间左端点和左子树的左端点是相同的,但次数却不一定相同。最简单的比如两个值相同的叶子节点合并,合并区间的左端点次数为2。右端点也同样存在这个问题。只要想到了这一点,解决起来并不麻烦。只有左子树所有元素完全相同,和右子树的左端点也相同时,才会出现区间左端点次数不等于左子树左端点的情况。又由于原数组是有序,所以只要左子树的左端点等于右子树的左端点,那它们中间的值就全都相等。对于右子树情况完全相同。

 

2.查询时,要注意处理好跨区间的查询,因为你的区间可能不在全部区间里,需要你的处理,具体看代码。

代码实现:

#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 1000000+5
typedef long long ll;
ll a[N];
int n,m;
// 线段树的每个节点维护五个值
// 左端的数,左端数在本区间内的个数
// 右端的数,右端数在本区间内的个数
// 本区间内的最大出现次数
int L[N], Lc[N], R[N], Rc[N], S[N];
struct node  //线段树
{
    int l,r;
}tree[N*4];
void build(int p,int l,int r)  //线段树建树
{
	tree[p].l=l;
	tree[p].r=r;
    if (l==r)   //叶子节点
    {
		L[p] = R[p] = a[l];
		Lc[p] = Rc[p] = 1;
		S[p] = 1;
        return;
    }
    
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    
    // 更新 S[p]
	int temp = 0;
	if(R[p<<1] == L[p<<1|1]) 
	temp = Rc[p<<1] + Lc[p<<1|1];
	temp = max(temp, S[p<<1]);
	S[p] = max(temp, S[p<<1|1]);
	
	// 更新 L[p] 和 R[p]
	L[p] = L[p<<1];
	R[p] = R[p<<1|1];  
	
	// 更新 Lc[p] 和 Rc[p]
 
	// 如果左儿子的左端点和右儿子的左端点相等
	// 则本区间的左端点次数等于它俩加和
	// 右端点也一样
	if(L[p<<1] == L[p<<1|1]) 
		Lc[p] = Lc[p<<1] + Lc[p<<1|1];
	else Lc[p] = Lc[p<<1];
	
	if(R[p<<1] == R[p<<1|1]) 
	   Rc[p] = Rc[p<<1] + Rc[p<<1|1];
	else Rc[p] = Rc[p<<1|1];
}  
 
ll query(int x,int l,int r)  //线段树区间查询
{  
    if (l<=tree[x].l&&r>=tree[x].r) 
    	return S[x];  //找到
    	
    int mid=(tree[x].l+tree[x].r)>>1;
    
    ll ans=0;
    int p=0,q=0;
    if (l<=mid) p=query(x<<1,l,r);
    if (r>mid)  q=query(x<<1|1,l,r);
    
	ans =max(p,q);
	// 如果左右儿子都出现在查询区间内
	// 且左儿子和右儿子可以连接
	// 需要考察左右儿子连接处是否出现了更大的值
	if(p>0&&q>0&&R[x<<1]==L[x<<1|1])
	{
		//一定要注意在查询区间范围内求解,用min原因一定要在查询区间范围内求解
		//连接右儿子
		ll temp = min(Rc[x<<1], mid-l+1);
		//连接左儿子
		temp += min(Lc[x<<1|1], r-mid);
		ans = max((ll)temp, ans);
	}
    return ans;
}
int main()
{
    while(scanf("%d",&n))
    {
     if(n==0) break;
     scanf("%d",&m);
	for (int i=1;i<=n;i++)
	{
	 scanf("%lld",&a[i]);
	}
     build(1,1,n);    
     while(m--)
	{
        int l, r;
        scanf("%d %d", &l, &r);
        printf("%lld\n",query(1,l,r));
        
    }
    
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/84075726