EOJ2458(离散化+线段树)

本文介绍了一种利用线段树解决区间内最长相等点序列的问题。通过对数据进行离散化处理,减少了树的复杂度。在查询过程中,通过自定义的结构体实现了高效的区间查询,最终给出了一段AC代码作为实现示例。

线段树的基本概念及操作:http://blog.youkuaiyun.com/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);
    }
}
### EOJ2654 题目解析与解法建议 EOJ2654 是华东师范大学在线评测系统(EOJ)中的一道编程题目。根据EOJ系统的常见题型和风格,这类题目通常涉及基础的数据结构操作、算法实现或数学建模。虽然没有直接提及EOJ2654的具体题目内容,但可以从EOJ系统的典型题目特征出发,结合常见的编程题类型,给出可能的解题思路与实现方法。 #### 题目类型推测 EOJ系统中常见的题目包括但不限于: - 数值计算与数学建模 - 字符串处理与模式匹配 - 数据结构操作(如栈、队列、链表等) - 图论与搜索算法 - 动态规划与贪心策略 根据题目编号(2654)以及EOJ的出题规律,该题可能属于**中等难度**,可能涉及**数学建模**或**字符串处理**。 #### 示例解法思路(假设题目为字符串处理) 假设题目要求判断某个字符串是否为回文串(Palindrome),可以采用如下C++实现: ```cpp #include <iostream> #include <string> #include <algorithm> using namespace std; int main() { string s; cin >> s; string rev = s; reverse(rev.begin(), rev.end()); if (s == rev) { cout << "Yes" << endl; } else { cout << "No" << endl; } return 0; } ``` #### 示例解法思路(假设题目为数学建模) 若题目要求求解某个数列的第n项,例如斐波那契数列,可以使用递归或迭代方法。以下是迭代方法的实现: ```cpp #include <iostream> using namespace std; long long fib(int n) { long long a = 0, b = 1, c; if (n == 0) return a; for (int i = 2; i <= n; i++) { c = a + b; a = b; b = c; } return b; } int main() { int n; cin >> n; cout << fib(n) << endl; return 0; } ``` #### 注意事项 在EOJ系统中,需要注意以下几点以避免运行时错误或超时: 1. **输入输出效率**:对于大规模输入数据,建议使用`scanf`和`printf`代替`cin`和`cout`以提高效率[^1]。 2. **数据类型选择**:在涉及大数运算时,应使用`long long`等大整数类型以防止溢出[^4]。 3. **边界条件处理**:特别注意输入数据的边界情况,如最小值、最大值等。 4. **代码简洁性与可读性**:保持代码结构清晰,避免不必要的复杂逻辑,以便调试与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值