[UVa11235]Frequent values

题目大意:给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数。

解题思路:由于是非降序排列,所有相同的数都是连在一起的。

本题可用RMQ做,但是我不会啊。 其实这题可以直接用线段树做(什么?RMQ可以用线段树做?我还是不会啊),不过需要保存三个东西,该区间出现最多的数出现的次数,该区间最左边的数出现的次数,该区间最右边出现的次数。

为什么要保存左边和右边的出现次数呢?例如区间$[1,10]$分为区间$[1,5]$和$[6,10]$,那么$[1,5]$的右边就有可能和$[6,10]$的左边拼成一段出现次数更多的序列,所以要保存这两个值,并计算两个区间拼接后的最大值和原最大值哪个更优。查询时同理。

C++ Code:

#include<iostream>
using namespace std;
int n,m,a[100001];
struct node{
	int Ls,Rs,s;
	node(int l=0,int r=0,int s=0):Ls(l),Rs(r),s(s){}
}d[400004];
inline int max(int a,int b){return(a>b)?a:b;}
void bt(int l,int r,int o){
	if(l==r){
		d[o]=node(1,1,1);
		return;
	}
	int mid=l+r>>1;
	bt(l,mid,o<<1);
	bt(mid+1,r,o<<1|1);
	d[o].s=max(d[o<<1].s,d[o<<1|1].s);
	if(a[mid]==a[mid+1])d[o].s=max(d[o].s,d[o<<1].Rs+d[o<<1|1].Ls);
	//如果左子区间的最右边的值等于右子区间的最左边的值,那么两边就能拼起来,形成一个更长的段
	d[o].Ls=d[o<<1].Ls;
	d[o].Rs=d[o<<1|1].Rs;
	if(a[mid]==a[mid+1]){
		if(d[o].Ls==mid-l+1)
		d[o].Ls+=d[o<<1|1].Ls;
		//如果左子区间的最右边的值等于右子区间的最左边的值,而左子区间刚好都是一个数,那么就能和右边拼起来
		if(d[o].Rs==r-mid)
		d[o].Rs+=d[o<<1].Rs;
		//右子区同理
	}
}
node query(int l,int r,int o,const int L,const int R,int ll,int rr){
	if(L<=l&&r<=R)return d[o];
	int mid=l+r>>1;
	node ld,rd,nd;
	if(L<=mid)ld=query(l,mid,o<<1,L,R,ll,mid);
	if(mid<R)rd=query(mid+1,r,o<<1|1,L,R,mid+1,rr);
	if(ld.s==0)return rd;
	if(rd.s==0)return ld;
	nd.s=max(ld.s,rd.s);
	if(a[mid]==a[mid+1])
	nd.s=max(nd.s,ld.Rs+rd.Ls);
	nd.Ls=ld.Ls;
	nd.Rs=rd.Rs;
	if(a[mid]==a[mid+1]){
		if(nd.Ls==mid-ll+1)
		nd.Ls+=rd.Ls;
		if(nd.Rs==rr-mid)
		nd.Rs+=ld.Rs;
	}
	return nd;
}
int main(){
	ios::sync_with_stdio(false);
	while(cin>>n>>m){
		for(int i=1;i<=n;++i)cin>>a[i];
		bt(1,n,1);
		while(m--){
			int x,y;
			cin>>x>>y;
			cout<<query(1,n,1,x,y,x,y).s<<endl;
		}
	}
	return 0;
}
时间: 2024-10-16 14:02:58

[UVa11235]Frequent values的相关文章

【暑假】[实用数据结构]UVa11235 Frequent values

UVa 11235 Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11241   Accepted: 4110 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several qu

uva11235(Frequent values)(HDU1806)

题目地址:Frequent values 题目大意.解题思路:  见白皮书p198. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int M=100100; 8 int a[M]; 9 int val[M],cn

[uva11235]Frequent values(RMQ,ST,离散化)

题目链接:https://vjudge.net/problem/UVA-11235 题意:给一串不递减数字,q次询问,每次查询[l,r]内出现次数最多的数字出现的次数. 查询分两部分:一部分是[l,r]为同一个数的区间,另一部分则是在上下界处截取一部分的情况. 首先离散化,后用l[],r[],v[]分别记录每一段相同数字的左右区间和出现次数.v可以直接由r-l+1更新得到. 第一部分更新ret后,接下来的rmq分三部分: 第一部分查询左边界截取一部分的数字的当前长度,第二部分查询右边界的,第三部

UVA-11235 Frequent values (RMQ)

题目大意:在一个长度为n的不降序列中,有m次询问,每次询问(i,j)表示在区间(i,j)中找出出现次数最多的元素的出现次数. 题目分析:因为序列有序,可以将序列分段,并且记录每段的元素个数.每一个元素所属的段num(i).每一个元素所属段的左端点l(i)及右端点r(i).那么对于每次询问: ans(i,j)=max(max(r(i)-i+1,j-l(j)+1),rmq(num(i)+1,num(j)-1)). ans(i,j)=r-j+1 (如果i与j属于同一段) 代码如下: # include

Uva11235 Frequent values (RMQ)

///对于每个询问(l,r),分为两个部分,前半部分求与l之前相同的数的个数直到t,后半部分从t开始直接用RMQ求解最大值就行了. ///最后结果为max(前半部分,后半部分). # include <algorithm> # include <string.h> # include <math.h> # include <iostream> using namespace std; int f[100100];///前i个有多少个相同的数 int dp[1

UVA11235 - Frequent values(BMQ)

题目链接 题目大意:可以一串不递减的序列,然后给你一个范围L,R,要求你返回L,R出现最多次的那个值的出现次数. 解题思路:将这个序列重新编码一下,把相同的数字标记成一段,然后用num记录是哪一段,用cnt记录一下出现了多少个相同的.然后查询的时候因为可能出现从一段中的某个部分开始的情况,所以要先将头和尾处理一下,标记每一段的最左端和最右端位置.中间完整的部分用BMQ. #include <cstdio> #include <cstring> #include <vector

[POJ3368][UVA11235] Frequent values[ST表]

题意:给出一个不降序列,有多个询问,询问[l,r]中出现次数最多的数的出现次数 多组数据 对于序列-1 -1 1 1 1 1 3 10 10 10 可以这么理解<-1,2>, <1, 4>, <3,1>, <10,3> cnt[i]记录这个数字的出现次数,lef[i]记录左端点,righ[i]记录右端点,belong[i]代表第i个数字属于哪一块 把块和数量丢进st表 然后对于区间[l,r],答案就是 \(min(r, righ[l])-l+1\),\(r-

POJ 3368:Frequent values RMQ

Frequent values 题目链接: http://poj.org/problem?id=3368 题意: 给出一个非递减序列,求区间内最多的数字的数量 题解: 水题,dp[i][j]记录从 i 开始2^j个数中的出现最多的数,合并dp[i][j]和dp[i+(1<<j)][j]得到dp[i][1<<(j+1)]的时候,由于序列是连续的,只要多考虑一个i+(1<<j)-1(即dp[i][j]所能到达的最右端)上得数字在区间内出现的次数就好了. 代码 #includ

uva 11235 - Frequent values(RMQ)

题目链接:uva 11235 - Frequent values 题目大意:给定一个非降序的整数数组,要求计算对于一些询问(i,j),回答ai,ai+1,-,aj中出现最多的数出现的次数. 解题思路:因为序列为非降序的,所以相同的数字肯定是靠在一起的,所以用o(n)的方法处理处每段相同数字的区间.然后对于每次询问: num[i]=num[j]:j?i+1 numi≠numj:max(RMQ(righti+1,reftj?1),max(righti?i+1,j?leftj+1)) #include