EOJ2458(离散化+线段树)

线段树的基本概念及操作: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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值