UVa 11235 - Frequent values(线段树版)

时间限制:3.000秒

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2176


  这次是Sparse-Table算法版本的修改版,改用线段树解决了RMQ问题,顺带验证下自己写的线段树模版管不管用。

  题目是回答一系列询问,求一段非降序排列的数组中某一段中出现次数最多的数出现的次数。

  先进行游程编码,例如-啊,-1,1,1,2,2,2,4可以编码成(-1, 1),(1, 2),(2, 3),(4, 1),记录下编码之后的数组每个下标对应原始数组的哪一段和原始数组的位置对应编码后数组的位置。查询时如果L和R在同一段中,结果为R-L+1,如果L和R在相邻的段中,则是L到L所在段结束位置元素个数和R所在段起始位置到R元素个数的最大值,如果L和R并非上面两种情况,则是L到L所在段结束位置元素个数,R所在段起始位置到R元素个数,L所在段和R所在段中间几段中的最大值,这三者中的最大值。


#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      

using std::min;
using std::max;

class SegTree { // Segment Tree
private:
    static const int MAXN = 10240000; // 数组的两倍长
    static const int inf = -1;
private:
    int minv[MAXN], len;
private:
    int query(const int &L, const int &R, const int &o, const int &l, const int &r) const {
        int m = l + (r - l) / 2, ans = inf;
        if(L <= l && r <= R) return minv[o];
        if(L <= m) ans = max(ans, query(L, R, o*2, l, m));
        if(m < R) ans = max(ans, query(L, R, o*2+1, m+1, r));
        return ans;
    }
    void update(const int &p, const int &v, const int &o, const int &l, const int &r) {
        int m = l + (r - l) / 2;
        if(l == r) minv[o] = v;
        else {
            if(p <= m) update(p, v, o*2, l, m);
            else update(p, v, o*2+1, m+1, r);
            minv[o] = max(minv[o*2], minv[o*2+1]);
        }
    }
    void init(const int *A, const int &o, const int &l, const int &r) {
        if(l == r) minv[o] = A[l];
        else {
            int m = l + (r - l) / 2;
            init(A, o*2, l, m);
            init(A, o*2+1, m+1, r);
            minv[o] = max(minv[o*2], minv[o*2+1]);
        }
    }
public:
    int init(const int *A, const int &length) { init(A, 1, 1, len = length); }
    int query(const int &L, const int &R) { return query(L, R, 1, 1, len); }
    void update(const int &p, const int &v) { return update(p, v, 1, 1, len); }
};

const int MAXN = 100000 + 10;

int n, q;
int a[MAXN], p[MAXN], left[MAXN], right[MAXN];
int s[MAXN], len;
SegTree tree;

inline void push() {
    len = 1;
    s[len] = 1, p[0] = len, left[len] = 0;
    for(int i = 1; i != n; ++i) {
        if(a[i] == a[i - 1]) ++s[len], p[i] = len;
        else {
            right[len++] = i - 1;
            s[len] = 1, p[i] = len, left[len] = i;
        }
    }
}

int main() {
    while(~scanf("%d", &n) && n) {
        scanf("%d", &q);
        for(int i = 0; i != n; ++i) scanf("%d", &a[i]);
        push();
        tree.init(s, len);

        for(int i = 0; i != q; ++i) {
            int L, R;
            scanf("%d%d", &L, &R);
            int l = p[--L], r = p[--R];
            if(l == r) printf("%d\n", R - L + 1);
            else if(l + 1 == r) printf("%d\n", max(right[l] - L + 1, R - left[r] + 1));
            else {
                int temp = max(right[l] - L + 1, R - left[r] + 1);
                printf("%d\n", max(tree.query(l + 1, r - 1), temp));
            }
        }
    }
}

     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值