POJ 3368 线段树,给定区间求连续不降序列的在该区间内出现最多的数

Frequent values

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 13771   Accepted: 5045

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

题目连接:http://poj.org/problem?id=3368

解法:数列是不降序列的,可以事先统计一次每一个数在哪个区间、每一个区间的初始位置与结束位置、把每个区间的数字的数量存成一个数组。

举个例子:

假设输入的数列为:1 1 2 2 2 3 3 3 3 5

那么处理之后统计每一个数在哪个区间就是:1 1 2 2 2 3 3 3 4 //把数组分为了4个区间,相同的数放同一个区间 ---记为数组c

初始位置和结束位置,这个好处理用一个结构体来记录:(1,2),(3,5),(6,9),(10,10)
-----记为结构体数组inv

最后一个数组,把每个数的数量装起来得到:2 3 4 1 ----记为数组b

做好这些操作之后,根据输入就可以求值

假设输入的查询为2,10

那么先查一下c[10]-c[2]的值,用于判断输入数据之间差了几个区间

这里算出来差了3个区间

那么先根据inv数组计算首尾两个区间分别有多少数据在2和10区间内,分别做好统计记为max1和max2

然后在计算出去首尾的剩下区间(都是全部区间都在查找范围内的)的最大长度

*转换思路之后其实是查找b数组2号位到3号位之间的区间最大值*

然后比较找一下b[2]和b[3]发现最大值max3=4

然后在max1和max2以及max3中寻找一个最大值就可以了,max1=1,max2=1

所以最大值为4

刚刚上面是一般情况,现在有两个特殊情况要处理

1、c[e]-c[s]==1

这种情况是代表两个区间是相邻的,所以没必要再到b数组里面去找了,因为这个时候已经没有剩下的区间,所以直接比较max1和max2的最大值即可

2、c[e]-c[s]==0

这种情况代表输入的值都在一个区间里面,所以max1和max2也都不存在,只需要直接e-s+1就可以求出答案

在一般情况下,寻找b数组中的区间最大值,可以用很多方法解决

我用的是线段树,但是寻找区间最大值可以用rmq,树状数组

不过这都不是关键,反正这个b数组是不会更新的,所以用什么数据结构来处理都是次要的,关键是方法

-----------------------------------------

以上为全部思路,下面贴出代码

code:

#include<stdio.h>

#define MAX_N 500000

struct node{
	int l;
	int r;
	int max;
};
struct msg{
	int value;
	int start;
	int end;
};
node tree[3*MAX_N];
int a[MAX_N+5];
int b[MAX_N+5];
int c[MAX_N+5];
msg inv[MAX_N+5];

int max(int x,int y){
	if(x>y)
		return x;
	else
		return y;
}

void swap(int &s,int &e){
	s=s^e;
	e=s^e;
	s=s^e;
}

void build_tree(int left,int right,int root){
	tree[root].l=left;
	tree[root].r=right;
	if(left==right){
		tree[root].max=b[left];
		return;
	}
	int mid=(left+right)/2;
	build_tree(left,mid,root*2);
	build_tree(mid+1,right,root*2+1);
	tree[root].max=max(tree[root*2].max,tree[root*2+1].max);
}

int find_max(int left,int right,int root){
	if(left==tree[root].l&&right==tree[root].r)
		return tree[root].max;
	int mid=(tree[root].l+tree[root].r)/2;
	if(right<=mid)
		return find_max(left,right,root*2);
	else if(left>mid)
		return find_max(left,right,root*2+1);
	else
		return max(find_max(left,mid,root*2),find_max(mid+1,right,root*2+1));
}

int main(){
	int n,m,i,len,inv_len,s,e;
	while(scanf("%d",&n)!=EOF){
		if(n==0)
			break;
		scanf("%d",&m);
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		len=0,inv_len=0;
		b[++len]=1;
		c[1]=1;
		inv[++inv_len].value=a[1];
		inv[inv_len].start=1;
		for(i=2;i<=n;i++){
			if(a[i]==a[i-1]){
				b[len]++;
				c[i]=c[i-1];
			}
			else{
				b[++len]=1;
				inv[inv_len].end=i-1;
				inv[++inv_len].value=a[i];
				inv[inv_len].start=i;
				c[i]=c[i-1]+1;
			}
		}
		inv[inv_len].end=n;
		build_tree(1,len,1);
		for(i=1;i<=m;i++){
			scanf("%d%d",&s,&e);
			if(s>e)
				swap(s,e);
			int q1=c[s];
			int q2=c[e];
			int ans;
			if(q2-q1==1){
				int max1=inv[q1].end-s+1;
				int max2=e-inv[q2].start+1;
				ans=max(max1,max2);
			}
			else if(q2-q1==0){
				ans=e-s+1;
			}
			else{
				int max1=inv[q1].end-s+1;
				int max2=e-inv[q2].start+1;
				int max3=find_max(c[inv[q1].end+1],c[inv[q2].start-1],1);
				ans=max(max(max1,max2),max3);
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}
时间: 2024-10-07 14:53:29

POJ 3368 线段树,给定区间求连续不降序列的在该区间内出现最多的数的相关文章

Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长

参考  https://www.cnblogs.com/null00/archive/2012/04/22/2464876.html #include <stdio.h> #include <algorithm> #define LEN 10000 using namespace std; struct Node { int left; int right; int count;//被覆盖次数 //所包含的区间数量,如三条[1,2],[2,3],[4,5]线段被覆盖,则line=2

poj 3368 线段树

这道题是要查询某个区间内数字出现的最大次数,序列不降,可以用线段树来做. 每个结点维护左右端点的值和出现次数(长度)以及该区间的Frequent values,然后向上合并即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100001; 7 int a[N]; 8 9 struct Node 10 { 11

POJ 3667 线段树的区间合并简单问题

题目大意:有一排标号1-N的房间.操作一:询问是不是有连续长度为a的空房间,有的话住进最左边(占用a个房间)操作二:将[a,a+b-1]的房间清空(腾出b个房间)思路:记录每个区间中“靠左”“靠右”“中间”的空房间线段树操作:update:区间替换query:询问满足条件的最左端点 题目链接: http://vjudge.net/problem/viewProblem.action?id=10354 题目操作: 因为这里找从最左边住起的房间,所以这里不能像常规地写query函数那样写了,终于发现

POJ 3667 线段树区间合并

http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很快能确定线段树要记录的信息做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析回忆一下RMQ问题,其实解决RMQ有很多方法,根本不需要用到线段树,用线段树解决RMQ,其实是利用线段树的性质来辅助解决这个问题回忆一下求矩形面积并或周长并的问题,一般使用的是扫描

poj 2777 线段树的区间更新

Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Chosen Problem Solving and Program design as an optional course, you are required to solve al

Mayor&#39;s posters POJ - 2528 线段树区间覆盖

//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=100010; int flag; struct node{ int l,r; //vis 是这块区域是否完全被覆盖 bool vis; }tr[N<<2]; struct point { int id; int x

POJ 2570 线段树

Potted Flower Time Limit: 2000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description The little cat takes over the management of a new park. There is a large circular statue in

poj 2886 线段树的更新+反素数

Who Gets the Most Candies? Time Limit: 5000 MS Memory Limit: 0 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description N children are sitting in a circle to play a game. The children are numbered from

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9