线段树的基本概念及操作:http://blog.csdn.net/metalseed/article/details/8039326
(引用一下)
这题题意就是问n个点序列,从小到大排列,问区间里最长的相等点的长度是多少。那么我们很容易想到线段树,将相同点相连即使一条线段,然后问区间里线段最长的是多少。因为题目给的是1 ≤ n, q ≤ 100000,所以直接建树势必复杂度将会很大,因此这里我们对初始数据先进行离散化。
具体操作就是将数据中相同的点放进一个点集,并用inf数组记录下每个点的点集下标,在建树的时候,直接通过每个点集求出max值。在查询的时候直接套用query模板,最后取得max值就OK了。
最后通过inf数组直接找出区间端点所在点集,从而判断区间覆盖了多少个点集,然后根据具体情况进行判断找出最大值就可以AC。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
struct ee
{
int l;
int r;
int max;
};
ee node[300010];
struct seg
{
int beg;
int end;
};
seg tree[400010];
int a[100001];
int inf[100001];
void build(int left,int right,int o)
{
node[o].l=left;
node[o].r=right;
if (left==right)
{
int k=left;
node[o].max=tree[k].end-tree[k].beg+1;
return;
}
int mid=(left+right)/2;
build(left,mid,o*2);
build(mid+1,right,(o*2)+1);
node[o].max=max(node[o*2].max,node[o*2+1].max);
}
int query(int left,int right,int o)
{
if (node[o].l==left&&node[o].r==right) return node[o].max;
if (right<=node[o*2].r) return query(left,right,o*2);
if (left>=node[o*2+1].l) return query(left,right,o*2+1);
int a=query(left,node[o*2].r,o*2);
int b=query(node[o*2+1].l,right,o*2+1);
return max(a,b);
}
int main()
{
int n,m,pre,k;
scanf("%d",&n);
while (n!=0)
{
scanf("%d",&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
pre=0;k=0;
for (int i=1;i<=n;i++)
{
if (a[i]!=pre)
{
pre=a[i];
k++;
tree[k].beg=i;
tree[k].end=i;
}
else tree[k].end=i;
inf[i]=k;
}
build(1,k,1);
while (m--)
{
int a,b,h1,h2;
scanf("%d%d",&a,&b);
h1=inf[a];
h2=inf[b];
if (h1==h2) printf("%d\n",b-a+1);//在同一条线段上
else//多个线段上
{
int n1=tree[h1].end-a+1;int n2=0;
int n3=b-tree[h2].beg+1;
if (h2-h1>1) n2=query(h1+1,h2-1,1);
printf("%d\n",max(max(n1,n3),n2));
}
}
scanf("%d",&n);
}
}