POJ_3368_线段树

来源:互联网 发布:java ee web profile 编辑:程序博客网 时间:2024/05/27 00:45

//============================================================================
// Name        : POJ_3368.cpp
// Author      : tiger
// Description : 给一个非递减序列,询问某一区间内数字出现最高频率
/*
 * 思路:在线段树的结点内设5个变量l、r、mx、lf、rf,[l,r]表示该结点的区间范围,
 * lf和rf分别表示元素a[l]和a[r]在区间内的出现频率,mx表示区间内的最高出现频率。
 * 假设区间[x,y]和[y+1,z]均被询问[i,j]覆盖,则可以分情况讨论区间[x,z]的mx值:
 * 若a[y]==a[y+1],则mx[x,y]=max{mx[x,y],mx[y+1,z],rf[x,y]+lf[y+1,z]}
 * 否则mx[x,y]=max{mx[x,y],mx[y+1,z]}
 * 线段树的应用还是不熟练!!!
 */
//============================================================================

#include <iostream>
using namespace std;
#define MAX 100000
#define min(a,b) (a<b?a:b)
struct NODE
{
    int l,r;
    int fl,fr;//该区间最左端元素和最右端元素出现频率
    int mx;//该区间最高频率
};
int s[MAX+2];
NODE tree[MAX*3];
void build(int v,int l,int r)
{
    tree[v].l = l;
    tree[v].r = r;
    if(l ==r )
    {
        tree[v].fl = 1;
        tree[v].fr = 1;
        tree[v].mx = 1;
        return;
    }
    int mid = (l+r)>>1;
    build(v*2,l,mid);
    build(v*2+1,mid+1,r);
    tree[v].fl = tree[v*2].fl;
    tree[v].fr = tree[v*2+1].fr;
    //左孩子最右边元素和右孩子最左边元素相同
    if(s[tree[v*2].r] == s[tree[v*2+1].l])
    {
        tree[v].mx = (tree[v*2].fr + tree[v*2+1].fl);
        //当前节点的最右边元素和右孩子坐左边元素相同,就说明右孩子所有元素相同并且和
        //左孩子右边部分元素相同,那么当前节点的右频率 = (tree[v*2].fr + tree[v*2+1].fl);
        if(s[tree[v].r] == s[tree[v*2+1].l])
        {
            tree[v].fr = tree[v].mx;
        }
        //原理同上
        if(s[tree[v].l] == s[tree[v*2].r])
        {
            tree[v].fl = tree[v].mx;
        }

    }else
    {
        tree[v].mx  = 1;
    }
    if(tree[v*2].mx > tree[v].mx  )
        tree[v].mx  = tree[v*2].mx;
    if(tree[v*2+1].mx > tree[v].mx  )
        tree[v].mx  = tree[v*2+1].mx;

}
int find(int v,int x,int y)
{
    if(x<= tree[v].l && y >= tree[v].r)
        return tree[v].mx;

    //询问区间在左孩子
    if(y <= tree[v*2].r)
    {
        return find(v*2,x,y);
    }
    //询问区间在右孩子
    if(x >= tree[v*2+1].l)
        return find(v*2+1,x,y);



    int max = 1,max1,max2;
    //左孩子最右边元素和右孩子最左边元素相同
    if(s[tree[v*2].r] == s[tree[v*2+1].l])
    {
        //询问区间有可能未把tree[v*2].fr个元素全包含进去,所以要取min(tree[v*2].r-x+1, tree[v*2].fr)
        max =min(tree[v*2].r-x+1, tree[v*2].fr) + min(y - tree[v*2+1].l+1,tree[v*2+1].fl);
    }
    max1 = find(v*2,x,tree[v*2].r);
    max2 = find(v*2+1,tree[v*2+1].l,y);
    if(max1 > max)
        max = max1;
    if(max2 > max)
        max = max2;
    return max;

}
int main() {
   // freopen("in","r",stdin);
    int i;
    int n,q;
    int x,y;
    while(scanf("%d %d",&n,&q)&&n)
    {
        for(i = 1; i <= n; i++)
            scanf("%d",s+i);
        build(1,1,n);
        while(q--)
        {
            scanf("%d %d",&x,&y);
            printf("%d/n",find(1,x,y));
        }
    }


    return 0;
}

原创粉丝点击