POJ 3368 线段树

思路:
先统计在第i个位置当前数字已经出现的次数。
维护两个数组,一个是当前位置的数字最后一次出现的位置,另一个是当前位置的数字第一次出现的位置
查找的时候分为两种情况:

  1. 没有和边界相交(意会意会)的数字中的最大值,注意右边界一定要不小于左边边界。
  2. 统计一下和边界相交的数字出现的次数… 如果整个区间是一个数的话要特判。
// by SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100005
int n,q,a[maxn],b[maxn],tree[maxn*4],f[maxn],xx,yy,jy,ans,jyx,jyy;
void build(int l,int r,int pos){
    if(l==r){tree[pos]=f[l];return;}
    int mid=(l+r)/2;
    build(l,mid,pos<<1);build(mid+1,r,pos<<1|1);
    tree[pos]=max(tree[pos<<1],tree[pos<<1|1]);
}
int query(int l,int r,int pos){
    if(l>=jyx&&r<=jyy)return tree[pos];
    int mid=(l+r)/2;
    if(mid>=jyy)return query(l,mid,pos<<1);
    else if(mid<jyx)return query(mid+1,r,pos<<1|1);
    else return max(query(l,mid,pos<<1),query(mid+1,r,pos<<1|1));
}
int main(){
    while(~scanf("%d",&n)&&n){
        scanf("%d",&q);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(i!=1&&a[i]==a[i-1])f[i]=f[i-1]+1;
            else f[i]=1;
        }
        jy=n;
        for(int i=n-1;i>=1;i--)
            if(f[i]==f[i+1]-1)a[i]=jy;
            else jy=i,a[i]=i;
        jy=1;
        for(int i=1;i<=n;i++)
            if(f[i+1]==f[i]+1)b[i]=jy;
            else b[i]=jy,jy=i+1;
        build(1,n,1);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&xx,&yy);
            jyx=a[xx]+1,jyy=b[yy]-1;
            if(jyx<=jyy)ans=max(query(1,n,1),max(jyx-xx,yy-jyy));
            else if(jyx<=yy&&jyy>=xx)ans=max(jyx-xx,yy-jyy);
            else ans=yy-xx+1;
            printf("%d\n",ans);
        }
    }
}

这里写图片描述

posted @ 2016-08-06 17:53  SiriusRen  阅读(157)  评论(0编辑  收藏  举报