题意:给你一段不下降的序列,q个询问,问[l,r]区间内连续出现次数最多的那个数的次数。
思路:
题意很像线段树,考虑用线段树怎么才能计算某个区间 连续出现次数最多的数呢?因为连续出现次数最多的数可能既不在它的左儿子也不在他的右儿子。刚好题目保证了是不减的序列,突破口就在这里,因为如果出现相同的数字,那么它们一定是连续的。所以我们只需要在普通的线段树中加上两个变量用来记录这段区间他的最左边那个数连续数的个数和在最右边那个数连续的个数。在我们求这段区间最大次数,需要多做一次比较(在这段区间的两个子区间中,当左子区间最右边数和右区间最左边的数相等时,取三个数的最大值)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct Tree
{
int left,right;
int maxx,lmaxx,rmaxx;
//maxx用来记录这段区间出现最多的次数的个数,
//lmaxx用来记录最左边那个数在这段区间连续的数的个数
//rmaxx用来记录最右边那个数在这段区间连续数的个数
};
Tree tree[maxn<<2];
int a[maxn];
void build(int id,int l,int r)
{
tree[id].left=l;
tree[id].right=r;
if(l==r)
{
tree[id].maxx=1;
tree[id].lmaxx=1;
tree[id].rmaxx=1;
}
else
{
int mid=(l+r)>>1;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
int tmp;
if(a[tree[id*2].right]==a[tree[id*2+1].left])
{
tmp=tree[id*2].rmaxx+tree[id*2+1].lmaxx;
}
else
tmp=0;
tree[id].maxx=max(max(tree[id*2].maxx,tree[id*2+1].maxx),tmp);
tree[id].lmaxx=tree[id*2].lmaxx;
//大区间的最左边的那个数和左子区间那个数值相同
if(tree[id*2].lmaxx==mid-l+1&&a[tree[id*2].right]==a[tree[id*2+1].left])
tree[id].lmaxx=mid-l+1+tree[id*2+1].lmaxx;
//判断左子区间里的数是否相同、以及是否等于右子区间最左边的那个数
//相同则lmaxx需要变化
tree[id].rmaxx=tree[id*2+1].rmaxx;
if(tree[id*2+1].rmaxx==r-mid&&a[tree[id*2].right]==a[tree[id*2+1].left])
tree[id].rmaxx=r-mid+tree[id*2].rmaxx;
//同理
}
}
int query(int id,int l,int r)
{
if(tree[id].left==l&&tree[id].right==r)
return tree[id].maxx;
else
{
int mid=(tree[id].left+tree[id].right)>>1;
if(r<=mid)
query(id*2,l,r);
else if(l>mid)
query(id*2+1,l,r);
else
{
int al=query(id*2,l,mid);
int ar=query(id*2+1,mid+1,r);
int ax=0;
if(a[tree[id*2].right]==a[tree[id*2+1].left])
ax=min(tree[id*2].rmaxx,mid-l+1)+min(tree[id*2+1].lmaxx,r-mid);
return max(max(al,ar),ax);
}
}
}
int main()
{
int n,q,i,l,r;
while(scanf("%d",&n))
{
if(n==0)
break;
scanf("%d",&q);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
while(q--)
{
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}
}