题目链接:
http://poj.org/problem?id=3368
题意:
给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数(保证给出n个数按升序排列)。
题解:
线段树存三个信息,L,M,R,分别表示左端点开始的最长连续子段的长度,整段区间最长连续子段长度,从右端点开始的最长连续子段的长度,具体查询与维护方法看代码:
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#define lson (id*2)
#define rson (id*2+1)
#define maxn (400005)
using namespace std;
int n,m,a[100005],L[maxn],R[maxn],M[maxn];
void pushup(int id,int l,int r)
{
int mid=(l+r)/2;
if (a[mid]==a[mid+1])
M[id]=max(max(M[lson],M[rson]),R[lson]+L[rson]);
else M[id]=max(M[lson],M[rson]);
if (L[lson]==mid-l+1 && a[mid]==a[mid+1]) L[id]=L[lson]+L[rson];
else L[id]=L[lson];
if (R[rson]==r-mid && a[mid]==a[mid+1]) R[id]=R[lson]+R[rson];
else R[id]=R[rson];
}
void build(int id,int l,int r)
{
if (l>r) return ;
if (l==r)
{
L[id]=1;R[id]=1;M[id]=1;
return ;
}
int mid=(l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(id,l,r);
}
int query(int id,int l,int r,int x,int y)
{
//if(l>y||r<x||r<l) return 0;
if (x<=l && y>=r) return M[id];
int mid=(l+r)/2;
if (y<=mid) return query(lson,l,mid,x,y);
if (x>=mid+1) return query(rson,mid+1,r,x,y);
int m1,m2,m3;
if (a[mid]==a[mid+1])
m1=min(R[lson],mid-x+1)+min(L[rson],y-mid);
m2=query(lson,l,mid,x,y);
m3=query(rson,mid+1,r,x,y);
return max(max(m1,m2),m3);
return 0;
}
int aa,bb;
int main()
{
while(scanf("%d",&n))
{
if (n==0) return 0;
scanf("%d",&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&aa,&bb);
printf("%d\n",query(1,1,n,aa,bb));
}
}
}