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

    hdu3308

    题意

    更新单个点,对于询问的区间,求最长连续子序列的长度。

    分析

    区间合并模板题。

    分析见代码。

    code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #define lson l, m, rt * 2
    #define rson m + 1, r, rt * 2 + 1
    using namespace std;
    const int MAXN = 1e5 + 10;
    int num[MAXN];
    // sum  当前节点所处区间内的最长连续上升子序列长度
    // lsum 当前节点所处区间从左端第一个点开始最长连续上升子序列长度
    // rsum 当前节点所处区间以右端点为结尾的最长连续上升子序列长度
    int sum[MAXN * 4], lsum[MAXN * 4], rsum[MAXN * 4];
    
    void pushup(int l, int r, int rt)
    {
        lsum[rt] = lsum[rt * 2];
        rsum[rt] = rsum[rt * 2 + 1];
        sum[rt] = max(sum[rt * 2], sum[rt * 2 + 1]);
        int m = (l + r) / 2;
        int len = r - l + 1;
        if(num[m] < num[m + 1]) // 区间合并
        {
            if(lsum[rt] == len - len / 2) lsum[rt] += lsum[rt * 2 + 1]; // lsum[rt] = lsum[rt * 2]区间为递增区间,所以可以和右边的部分区间可以合并
            if(rsum[rt] == len / 2) rsum[rt] += rsum[rt * 2];           // 同理
            sum[rt] = max(sum[rt], rsum[rt * 2] + lsum[rt * 2 + 1]);    // 这个两个区间是以 m 为割点分割的,合并区间
        }
    }
    void build(int l, int r, int rt)
    {
        if(l == r)
        {
            sum[rt] = lsum[rt] = rsum[rt] = 1;
            return;
        }
        int m = (l + r) / 2;
        build(lson);
        build(rson);
        pushup(l, r, rt);
    }
    void update(int p, int l, int r, int rt)
    {
        if(l == r) return;
        int m = (l + r) / 2;
        if(p <= m) update(p, lson);
        else update(p, rson);
        pushup(l, r, rt);
    }
    int query(int L, int R, int l, int r, int rt)
    {
        if(L <= l && r <= R) return sum[rt];
        int m = (l + r) / 2;
        if(m >= R) return query(L, R, lson);
        if(m < L) return query(L, R, rson);
        int a = query(L, R, lson);
        int b = query(L, R, rson);
        int ans = max(a, b);
        if(num[m] < num[m + 1]) // 此时 L <= m < R ,保证答案一定在[L, R]区间内
        {
            int c = min(m - L + 1, rsum[rt * 2]) + min(R - m, lsum[rt * 2 + 1]);
            ans = max(ans, c);
        }
        return ans;
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int n, m;
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++) scanf("%d", &num[i]);
            build(1, n, 1);
            while(m--)
            {
                char c[2]; int A, B;
                scanf("%s%d%d", c, &A, &B); A++;
                if(c[0] == 'U')
                {
                    num[A] = B;
                    update(A, 1, n, 1);
                }
                else
                {
                    printf("%d
    ", query(A, B + 1, 1, n, 1));
                }
            }
        }
        return 0;
    }
    

    I. Candies

    题意

    给定一个只由A、B组成的序列,区间更新操作将选定区间的所有值变成指定的值,区间查询操作查询区间内最大连续B的数量。

    分析

    区间更新,区间合并问题。
    加入延迟标记,和区间求和较类似。

    本题可以用01序列代替AB序列,
    sum 数组内存的就是最大有多少个连续的 1 的个数了,
    suml 数组表示从当前节点区间左端点开始的最大连续 1 的个数,
    sumr 数组表示以当前节点区间右端点结束的最大连续 1 的个数,

    当区间赋值为 A 时,把在那个区间内的节点 的 sum 数组置为 0 即可。

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define lson l, m, rt * 2
    #define rson m + 1, r, rt * 2 + 1
    using namespace std;
    typedef pair<int, int> P;
    typedef long long ll;
    const int INF = 1e9;
    const int MAXN = 1e6 + 10;
    char s[MAXN];
    int sum[MAXN * 4], suml[MAXN * 4], sumr[MAXN * 4], lazy[MAXN * 4];
    void pushup(int l, int r, int rt)
    {
        suml[rt] = suml[rt * 2];
        sumr[rt] = sumr[rt * 2 + 1];
        sum[rt] = max(sum[rt * 2], sum[rt * 2 + 1]);
        int m = (l + r) / 2;
        int len = r - l + 1;
        if(suml[rt] == len - len / 2) suml[rt] += suml[rt * 2 + 1];
        if(sumr[rt] == len / 2) sumr[rt] += sumr[rt * 2];
        sum[rt] = max(sum[rt], sumr[rt * 2] + suml[rt * 2 + 1]);
    }
    void pushdown(int l, int r, int rt)
    {
        int len = r - l + 1;
        if(lazy[rt] == 2)
        {
            sum[rt * 2] = suml[rt * 2] = sumr[rt * 2] = len - len / 2;
            sum[rt * 2 + 1] = suml[rt * 2 + 1] = sumr[rt * 2 + 1] = len / 2;
            lazy[rt * 2] = lazy[rt * 2 + 1] = lazy[rt];
        }
        else if(lazy[rt])
        {
            sum[rt * 2] = suml[rt * 2] = sumr[rt * 2] = 0;
            sum[rt * 2 + 1] = suml[rt * 2 + 1] = sumr[rt * 2 + 1] = 0;
            lazy[rt * 2] = lazy[rt * 2 + 1] = lazy[rt];
        }
        lazy[rt] = 0;
    }
    void build(int l, int r, int rt)
    {
        lazy[rt] = 0;
        if(l == r)
        {
            sum[rt] = suml[rt] = sumr[rt] = (s[l] == 'B');
            return;
        }
        int m = (l + r) / 2;
        build(lson);
        build(rson);
        pushup(l, r, rt);
    }
    void update(int L, int R, int p, int l, int r, int rt)
    {
        if(L <= l && r <= R)
        {
            lazy[rt] = p;
            suml[rt] = sumr[rt] = sum[rt] = (p - 1) * (r - l + 1);
            return;
        }
        pushdown(l, r, rt);
        int m = (l + r) / 2;
        if(m >= L) update(L, R, p, lson);
        if(m < R) update(L, R, p, rson);
        pushup(l, r, rt);
    }
    int query(int L, int R, int l, int r, int rt)
    {
        if(L <= l && r <= R) return sum[rt];
        pushdown(l, r, rt);
        int m = (l + r) / 2;
        if(m >= R) return query(L, R, lson);
        if(m < L) return query(L, R, rson);
        int ans = max(query(L, R, lson), query(L, R, rson));
        int c = min(m - L + 1, sumr[2 * rt]) + min(R - m, suml[rt * 2 + 1]);
        ans = max(ans, c);
        return ans;
    }
    int main()
    {
        int T, c = 1;
        scanf("%d", &T);
        while(T--)
        {
            int n, m;
            scanf("%d%d", &n, &m);
            scanf("%s", s + 1);
            build(1, n, 1);
            printf("Case #%d:
    ", c++);
            while(m--)
            {
                int c;
                scanf("%d", &c);
                int x, y, z;
                if(c == 1)
                {
                    scanf("%d%d%d", &x, &y, &z);
                    update(x, y, z, 1, n, 1);
                }
                else
                {
                    scanf("%d%d", &x, &y);
                    printf("%d
    ", query(x, y, 1, n, 1));
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    【Project4】【技术总结】
    JS实现新浪微博搜索框提示的特效代码
    动态效果显示的人物结构的关系图
    人立方
    javascript 动态显示复杂结构的网络关系图
    Adding a Timepicker to jQuery UI Datepicker
    【Framework】【清单】
    JavaScript[Mount]
    10 jQuery Time Picker Plugins
    CSS样式切换技巧 动态更换网页色彩皮肤(转)
  • 原文地址:https://www.cnblogs.com/ftae/p/6791235.html
Copyright © 2011-2022 走看看