zoukankan      html  css  js  c++  java
  • HDU3308 线段树区间合并

      题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并。

      线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实现区间合并操作。


    解法:

      由于对于一个区间的最长序列来说,最优解要么完全在左半序列,要么完全在右半序列,要么跨越中间点。所以可以构造线段树,维护结点区间的三个元素:最长上升前缀len[].l,最长上升后缀len[].r,最长上升序列len[].m。所以对于一个区间来说,有这样两种情况:

    1. 左儿子最右边的值 >= 右儿子最左边的值(不能区间合并)

      前缀 = 左儿子的前缀    len[rt].l = len[rt << 1].l

      后缀 = 右儿子的后缀    len[rt].r = len[rt << 1 | 1].r

      最长序列 = 左右儿子的最长序列的最大值    len[rt].m = max(len[rt << 1].m , len[rt << 1 | 1].m)

    2. 左儿子最右边的值 < 右儿子最左边的值(可以区间合并)

      前缀 = (左儿子的前缀 == 左儿子的长度) ? 左儿子的前缀 + 右儿子的前缀 : 左儿子的前缀

      后缀 = (右儿子的后缀 == 右儿子的长度) ? 右儿子的后缀 + 左儿子的后缀 : 右儿子的后缀

      最长序列 = max(左儿子的后缀 + 右儿子的前缀 , 左儿子的最长序列, 右儿子的最长序列)

      

      还有要注意的是query()函数,在查询的时候,完全在区间左半边或者完全在区间右半边的情况比较好办,如果是两边都有的话这样来考虑:

    1.区间不能合并:这种情况可以直接返回左右儿子查询的最大值即可;

    2.区间可以合并:左右儿子合并后的长度、左右儿子的查询,这三者取最大值;这里要注意合并左右儿子的时候不能超过查询区间的长度。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <vector>
    #include <string>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define LL __int64
    #define flag a[m + 1] > a[m]    //区间合并的标志
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int maxn = 100000 + 5;
    struct Max_len {    //三个元素
        int l , r , m;
    } len[maxn << 2];
    int a[maxn];
    
    void PushUp(int l , int r , int rt)
    {          //在PushUp中实现区间合并
        int m = (l + r) >> 1;
        len[rt].l = len[rt << 1].l;
        if(flag && len[rt].l == (m - l + 1))
            len[rt].l += len[rt << 1 | 1].l;
        
        len[rt].r = len[rt << 1 | 1].r;
        if(flag && len[rt].r == (r - m))
            len[rt].r += len[rt << 1].r;
    
        if(flag) {
            len[rt].m = max(len[rt << 1].r + len[rt << 1 | 1].l , 
                max(len[rt << 1].m , len[rt << 1 | 1].m));
        } else {
            len[rt].m = max(len[rt << 1].m , len[rt << 1 | 1].m);
        }
    }
    void build(int l , int r , int rt)
    {
        if(l == r) {
            scanf("%d" , &a[l]);
            len[rt].l = len[rt].r = len[rt].m = 1;
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        PushUp(l , r , rt);
    }
    void update(int p , int x , int l , int r , int rt) 
    {
        if(l == r) {
            a[p] = x;
            return;
        }
        int m = (l + r) >> 1;
        if(p <= m)
            update(p , x , lson);
        else
            update(p , x , rson);
        PushUp(l , r , rt);
    }
    int query(int L , int R , int l , int r , int rt)
    {
        if(L <= l && R >= r) {
            return len[rt].m;
        }
        int m = (l + r) >> 1;
        if(R <= m)
            return query(L , R , lson);
        else if(L > m)
            return query(L , R , rson);
        else {
            int ll = query(L , R , lson);
            int rr = query(L , R , rson);
            int ret = max(ll , rr);
            if(flag) {
                ll = min(len[rt << 1].r , m - L + 1);    //不能超过查询区间的长度
                rr = min(len[rt << 1 | 1].l , R - m);
                ret = max(ret , ll + rr);
            }
            return ret;
        }
    }
    int main() 
    {
        int n , m , T;
        int a , b;
        char ch[3];
        cin >> T;
        while(T--) {
            scanf("%d %d" , &n , &m);
            build(0 , n - 1 , 1);
            while(m--) {
                scanf("%s" , ch);
                if(ch[0] == 'U') {
                    scanf("%d %d" , &a , &b);
                    update(a , b , 0 , n - 1 , 1);
                } else {
                    scanf("%d %d" , &a , &b);
                    printf("%d
    " , query(a , b , 0 , n - 1 , 1));
                }
            }
        }
        return 0;
    }

     

  • 相关阅读:
    史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现(Eureka)
    漫谈《大型网站技术架构》
    如何使用MongoDB+Springboot实现分布式ID?
    IOS UIView 01-View开始深入 绘制像素到屏幕上
    IOS 多线程04-GCD详解 底层并发 API
    IOS 多线程05-OperationQueue 、GCD详解
    IOS 多线程02-pthread 、 NSThread 、GCD 、NSOperationQueue、NSRunLoop
    IOS 公共类-数字处理
    React Native02-开始运行 Android篇
    React Native01-开始 Windows环境安装配置篇
  • 原文地址:https://www.cnblogs.com/H-Vking/p/4392533.html
Copyright © 2011-2022 走看看