UVA 11235 线段树区间合并 & 离散化

传送门 : UVA 11235

题意

  1. 给定一个长为n的数列, 给定q个查询, 查询[l, r]内出现最多数字的出现次数

题解

  1. 常规解法: 线段树区间合并, 需要注意的是, 查询时的区间合并不能忽略
  2. 离散化,离散的运用:将连续的相等的一个区间的点集,聚集为线段树的一个节点,并且在这个节点上有信息能体现出这个区间的性质。

code:


/*
 *adrui's submission
 *Language : C++
 *Reault : Accepted
 *Favorite : Dragon Balls
 *Love : ll
 *
 *Standing in the Hall of Fame
 */
//区间合并
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define inf 0x7f7f7f7f
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r

const int maxn(1e5 + 7);

int n, q;

struct segment_tree
{
    int l;
    int r;
    int ans, lAns, rAns;       //l, r为左右端点值
                               //lAns, rAns为左右端连续的相同个数, ans为此区间ans
} node[maxn << 2];

int num[maxn];

void pushUp(segment_tree &q, segment_tree q1, segment_tree q2, int l, int r)
{
    q.l = q1.l;
    q.r = q2.r;
    q.lAns = q1.lAns;
    q.rAns = q2.rAns;

    if(q1.r != q2.l) //直接维护ans
    {
        q.ans = max(q1.ans, q2.ans);
    }
    else            //维护ans, lAns, rAns
    {
        if(q1.lAns == mid - l + 1)
            q.lAns +=  q2.lAns;
        if(q2.rAns == r - mid)
            q.rAns += q1.rAns;
        q.ans = max(q1.rAns + q2.lAns, max(q1.ans, q2.ans));
    }

}

void build(int rt, int l, int r)
{
    if( l == r)
    {
        cin >> node[rt].r;
        node[rt].l = node[rt].r;
        node[rt].ans = node[rt].lAns = node[rt].rAns = 1;
        return;
    }

    build(ls);
    build(rs);

    pushUp(node[rt], node[rt << 1], node[rt << 1 | 1], l, r);
}

segment_tree query(int rt, int l, int r, int ql, int qr)
{
    if(ql <= l && qr >= r)
    {
        return node[rt];
    }

    segment_tree q, q1, q2;
    if(ql <= mid && mid < qr)//如果查询区间被mid分割, 则分开查询并合并
    {
        q1 = query(ls, ql, qr);
        q2 = query(rs, ql, qr);
        pushUp(q, q1, q2, l, r);
    }
    else                     //反之, 只有一个区间要查询
    {
        if(ql <= mid) q = query(ls, ql, qr);
        if(qr > mid)  q = query(rs, ql, qr);
    }

    return q;
}

int main()
{
#if debug
    freopen("in.txt", "r", stdin);
#endif //debug
    cin.tie(0);
    cin.sync_with_stdio(false);

    int a, b;
    while(cin >> n, n)
    {
        cin >> q;
        build(1, 1, n);//建树

        while(q--)
        {
            cin >> a >> b;
            cout << query(1, 1, n, a, b).ans << endl;
        }
    }
    return 0;
}

/*
 *adrui's submission
 *Language : C++
 *Reault : Accepted
 *Favorite : Dragon Balls
 *Love : ll
 *
 *Standing in the Hall of Fame
 */

//线段树 + 离散化
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define inf 0x7f7f7f7f
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r

const int maxn(1e5 + 7);

int n, q;

struct{
    int l;
    int r;
    int len;
}node[maxn << 2];

struct{
    int l;
    int r;
}seg[maxn];

int num[maxn], Hash[maxn];

void pushUp(int rt){
    node[rt].len = max(node[rt << 1].len, node[rt << 1 |1].len);
}

void build(int rt, int l, int r){
    if( l == r){
        node[rt].len = seg[l].r - seg[l].l + 1;
        return;
    }

    build(ls);
    build(rs);

    pushUp(rt);
}

int query(int rt, int l, int r, int ql, int qr){
    if(ql <= l && qr >= r){
        return node[rt].len;
    }

    int res = -inf;

    if(ql <= mid) res = max(res, query(ls, ql, qr));
    if(qr > mid)  res = max(res, query(rs, ql, qr));

    return res;
}
int main(){
#if debug
    freopen("in.txt", "r", stdin);
#endif //debug
    cin.tie(0);
    cin.sync_with_stdio(false);

    int a, b;
    while(cin >> n, n){
        cin >> q;
        int cnt = 0, pre = inf;

        for(int i = 1; i <= n; i++){
            cin >> num[i];
            if(num[i] != pre){
                pre = num[i];
                cnt++;
                seg[cnt].l = i;
                seg[cnt].r = i;
            }else{
                seg[cnt].r = i;
            }

            Hash[i] = cnt;//hash下用于记录当前点所在离散的下标
        }

        build(1, 1, cnt);//离散化建树

        while(q--){
            cin >> a >> b;
            int pos1 = Hash[a], pos2 = Hash[b], ans;//hash获取

            if(pos1 == pos2){//如果a, b在同一离散点内
                ans = b - a + 1; 
            }
            else{            //不同离散点, len1, len3分别为a, b所在离散点的连续长度,len2为中间离散点的最大ans
                int len1 = seg[pos1].r - a + 1;
                int len2 = 0;
                int len3 = b - seg[pos2].l + 1;
                if(pos2 ^ pos1 ^ 1){//a, b中间有离散点, 查询最大
                    len2 = query(1, 1, cnt, pos1 + 1, pos2 - 1);
                    }

                ans = max(len1, max(len2, len3));
            }

            cout << ans << endl;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值