您的位置:首页 > 产品设计 > UI/UE

Frequent values(线段树+离散化)

2014-02-20 16:45 369 查看
http://poj.org/problem?id=3368

题意:给出一个非降序排列的整数数组,对于询问(i,j),输出区间[i,j]中出现最多的值的次数。

思路:经典的RMQ,不过我用线段树做的。首先要离散化,因为是非降序的,所以相同的数是连续的,可以将相同的数分在同一个块中,将块中的信息存储起来,然后将其看成一个点,就可以用线段树进行查询了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=1000010;
struct node
{
int l,r;
int Max;
} Tree[N*4];
struct point//记录每块的信息
{
int s,t;//s起始位置,t结束位置
int cnt;//块中的数出现的次数
} block
;
int v
,num
;//num[i]表示第i个数被分在第几块
void build(int l,int r,int rt)
{
Tree[rt].l = l;
Tree[rt].r = r;
if (l==r)
{
Tree[rt].Max = block[l].cnt;
return ;
}
int mid = (l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
Tree[rt].Max=max(Tree[rt<<1].Max,Tree[rt<<1|1].Max);
}
int Query(int l,int r,int rt)
{
if(Tree[rt].l==l&&Tree[rt].r==r)
return Tree[rt].Max;
int mid=(Tree[rt].l+Tree[rt].r)>>1;
if (r <= mid)
return Query(l,r,rt<<1);
else if (l > mid)
return Query(l,r,rt<<1|1);
else
return max(Query(l,mid,rt<<1),Query(mid+1,r,rt<<1|1));
}
int main()
{
int n,q;
while(~scanf("%d%d",&n,&q)&&n)
{
memset(block,0,sizeof(block));
for (int i = 1; i <= n; i++)
scanf("%d",&v[i]);
int m=1;
block[m].s=1;
for (int i = 1; i <= n; i++)//将相同的数分在同一块
{
num[i]=m;
if(v[i]!=v[i+1]||i==n)
{
block[m].t = i;
block[m].cnt=block[m].t-block[m].s+1;
block[++m].s = i+1;
}
}
build(1,m-1,1);//将每一块看成一个点,建树
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
if (num[l]==num[r])//在同一个块里,则[l,r]是连续的相同的数
printf("%d\n",r-l+1);
else               //不在同一个块里
{
int cnt1 = block[num[l]].t-l+1;//l所在块中,区间[l,block[num[l]].t]中相同的数的次数
int cnt3 = r-block[num[r]].s+1;//r所在块中,区间[block[num[r]].s,r]中相同的数的次数
int cnt2 = 0;
if (num[r]-num[l]>1)//大于两个块
cnt2 = Query(num[l]+1,num[r]-1,1);//中间块相同数出现的最多次数
int ans = max(max(cnt1,cnt3),cnt2);
printf("%d\n",ans);
}
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: