线段树之五

#include <iostream>         //poj 3368 Frequent values 
using namespace std;
struct segment
{
int l,r,freq;
}tree[
400005];
int arr[100005],group[100005][2],curr,attach[100005];
void built_group(int n)
{
curr
=1;
group[curr][
0]=group[curr][1]=1;
attach[curr]
=1;
for(int i=2;i<=n;++i)
{
if(arr[i]==arr[i-1])
group[curr][
1]++;
else
{
++curr;
group[curr][
0]=group[curr][1]=i;
}
attach[i]
=curr; //记录原数组的元素属于哪个分组内,否则后面就得逐一去找它属于哪一组,必TLE
}
}
void built_tree(int n,int s,int t)
{
tree[n].l
=s;tree[n].r=t;
if(s==t)
{
tree[n].freq
=group[s][1]-group[s][0]+1;
}
else
{
int mid=(s+t)>>1;
built_tree(
2*n,s,mid);
built_tree(
2*n+1,mid+1,t);
tree[n].freq
=max(tree[2*n].freq,tree[2*n+1].freq);
}
}
int view_tree(int n,int s,int t)
{
if (tree[n].l==s&&tree[n].r==t)
return tree[n].freq;
else
{
int mid=(tree[n].l+tree[n].r)>>1,a=0,b=0;
if(s<=mid)
a
=view_tree(2*n,s,min(t,mid));
if(t>mid)
b
=view_tree(2*n+1,max(mid+1,s),t);
return max(a,b);
}
}
void query(int s,int t) //查询
{
int res,l_group=attach[s],r_group=attach[t];
if(l_group==r_group)
res
=t-s+1;
else
{
res
=max(group[l_group][1]-s+1,t-group[r_group][0]+1);
if(l_group+1<r_group)
res
=max(res,view_tree(1,l_group+1,r_group-1)); //这里要用到线段树
}
printf(
"%d\n",res);
}
int main()
{
int n,q,s,t;
while(scanf("%d",&n)&&n)
{
scanf(
"%d",&q);
for(int i=1;i<=n;++i)
scanf(
"%d",arr+i);
built_group(n);
built_tree(
1,1,n);
while(q--)
{
scanf(
"%d%d",&s,&t);
query(s,t);
}
}
return 0;
}

//首先对给出的原序列进行统计,将相同的数字放进同一组内,group[i][0],group[i][1],记录在原序列中该组起点和终点的位置
//用attach[i]=curr;记录原序列每个元素属于哪一组
//之后就是查询,比方说[s,t], l_group, r_group 为s,t的组号 l_group=attach[s],r_group=attach[t];
//1.如果s,t属于同一个组,那么区间长度就是我们想要的答 案 t-s+1;
//2.如果s,t组号相差1,说明该区间处于两个组,只要分别研究两侧的区间,取大值,max(group[l_group][1]-s+1,t-group[r_group][0]+1);
//3.如果s,t组号相差大于1,先取出两侧进行研究,取大值,然后再用线段树,算出中间的其他区间的最大值,与刚才的的值比较,再取出最大值

  

posted on 2011-07-17 02:01  sysu_mjc  阅读(108)  评论(0编辑  收藏  举报

导航