zoukankan      html  css  js  c++  java
  • 5W次单点修改,求最长的连续上升子序列 HDU 3308

    题目大意:给你n个数,m个操作。

    有两种操作:

    1.U x y 将数组第x位变为y  

    2. Q x y 问数组第x位到第y位连续最长子序列的长度。

    对于每次询问,输出连续最长子序列的长度

    思路:用线段树维护上升序列,每个端点维护:左边连续递增的len,右边连续递增的len,中间连续递增的len,左边val,右边val,和目前的len。然后不断更新即可。

    注意:如果左区间的最右边的值小于右区间最左边的值,则有一个待定答案是左儿子的右区间+右儿子的左区间

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    /*
    ①记录本身内部的序列长度
    ②要将区间合并的时候,rightson的left区间和leftson的right区间判断条件以后再合并。
    如果合并区间是对于两端的值
    */
    const int maxn = 1e5 + 5;
    struct Tree{
        int leftlen, rightlen, midlen, leftval, rightval, len;
    }tree[maxn << 2];
    int n, m;
    
    inline void pushup(int o){
        int lb = o << 1, rb = o << 1 | 1;
        int lbval = tree[lb].rightval, rbval = tree[rb].leftval;
        bool flag = false;
        tree[o].midlen = max(tree[lb].rightlen, max(tree[rb].leftlen, max(tree[lb].midlen, tree[rb].midlen)));
        if (lbval < rbval) {
            flag = true;
            tree[o].midlen = max(tree[lb].rightlen + tree[rb].leftlen, tree[o].midlen);
        }
    
        tree[o].leftlen = tree[lb].leftlen;
        if (tree[lb].rightlen == tree[lb].len && flag) tree[o].leftlen = tree[o].midlen;
    
        tree[o].rightlen = tree[rb].rightlen;
        if (tree[rb].leftlen == tree[rb].len && flag) tree[o].rightlen = tree[o].midlen;
        tree[o].leftval = tree[lb].leftval, tree[o].rightval = tree[rb].rightval;
    }
    
    void buildtree(int l, int r, int o){
        tree[o].len = r - l + 1;
        if (l == r){
            int val; scanf("%d", &val);
            tree[o].leftlen = tree[o].rightlen = tree[o].midlen = 1;
            tree[o].leftval = tree[o].rightval = val;
            return ;
        }
        int mid = (l + r) / 2;
        if (l <= mid) buildtree(l, mid, o << 1);
        if (r > mid) buildtree(mid + 1, r, o << 1 | 1);
        pushup(o);
        //printf("l = %d r = %d leftlen = %d rightlen = %d midlen = %d
    ", l, r, tree[o].leftlen, tree[o].rightlen, tree[o].midlen);
    }
    
    void update(int pos, int val, int l, int r, int o){
        if (pos == l && pos == r){
            tree[o].leftval = tree[o].rightval = val; return ;
        }
        int mid = (l + r) / 2;
        if (pos <= mid) update(pos, val, l, mid, o << 1);
        if (pos > mid) update(pos, val, mid + 1, r, o << 1 | 1);
        pushup(o);
    }
    
    int query(int ql, int qr, int l, int r, int o){
        int ans = 1;
        if (ql <= l && qr >= r){
            ans = max(ans, max(tree[o].leftlen, max(tree[o].rightlen, tree[o].midlen)));
            return ans;
        }
        int mid = (l + r) / 2;
        int t1 = -1, t2 = -1;
        if (mid >= ql){
            t1 = query(ql, qr, l, mid, o << 1);
        }
        if (mid < qr){
            t2 = query(ql, qr, mid + 1, r, o << 1 | 1);
        }
        ans = max(ans, max(t1, t2));
        ///如果左区间的最右边的值小于右区间最左边的值,则有一个待定答案是左儿子的右区间+右儿子的左区间
        if (tree[o << 1].rightval < tree[o << 1 | 1].leftval && t1 > 0 && t2 > 0){
            t1 = min(tree[o << 1].rightlen, mid - ql + 1) + min(tree[o << 1 | 1].leftlen, qr - mid);
            ans = max(ans, t1);
        }
        return ans;
    }
    
    int main(){
        int t; cin >> t;
        while (t--){
            scanf("%d%d", &n, &m);
            buildtree(1, n, 1);
            for (int i = 1; i <= m; i++){
                char ch[2]; int a, b;
                scanf("%s%d%d", ch, &a, &b);
                if (ch[0] == 'U'){
                    update(a + 1, b, 1, n, 1);
                }
                else {
                    printf("%d
    ", query(a + 1, b + 1, 1, n, 1));
                }
            }
        }
        return 0;
    }
    View Code

    关键:

    感觉和以前的一题CF很像,忘了是哪里的了......

  • 相关阅读:
    重写Django登录认证,实现用户名或者手机均可登录
    Django media文件夹详解
    Django admin使用
    python极验验证部署
    django 分页
    模板语言控制往哪个地址提交时,如果不填,默认往当前地址提交,也可以用request方法获取当前地址提交
    HashMap、Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别
    ArrayList、LinkedList、Vector、CopyOnWriteArrayList的区别和源码分析
    谈谈线程池的核心参数,描述核心流程、应该怎么正确使用
    深入CAS的底层实现机制,以及对应的使用风险
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6358782.html
Copyright © 2011-2022 走看看