• HDU 6406 Taotao Picks Apples & FJUT3592 做完其他题后才能做的题(线段树)题解


    题意(FJUT翻译HDU):

    钱陶陶家门前有一棵苹果树。 秋天来了,树上的n个苹果成熟了,淘淘会去采摘这些苹果。

    到园子里摘苹果时,淘淘将这些苹果从第一个苹果扫到最后一个。 如果当前的苹果是第一个苹果,或者它严格高于之前选择的苹果,那么淘淘将采摘这个苹果; 否则,他不会选择。

    题目来了:已知这些苹果的高度为h1,h2,⋯,hn,您需要回答一些独立的查询。 每个查询是两个整数p,q,表示如果第p个苹果的高度修改为q,询问当前淘淘将摘到的苹果的数量。 你能解决这个问题吗?

    思路:pre表示1~i的最大连续答案,tail代表i~n的最大连续答案。最终答案为p前,p,p后三部分的贡献和。

    预处理pre和tail。tail从后往前预处理,用二分(线段树)查找第一个比i位置大的数。

    然后每次找p前最大值下标preMax,ans += pre[preMax],为p前贡献。

    ans += q > a[preMax],为p的贡献。

    查找p后第一个大于前面所有数的值的下标tailMax,ans += tail[tailMax],为p后贡献。

    三者贡献和为总贡献。

    二分查找p后第一个大于前面所有数的值的下标一顿好写啊(微笑

    思考了半天发现是线段树写错了。显然(?)只有在L <= l && R >= r(就是说当前区间是查询区间子集)才能直接剪枝选择左儿子或者右儿子。

    代码:

    #include<set>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    const int maxn = 100000 + 10;
    const int seed = 131;
    const ll MOD = 1e9 + 7;
    const ll INF = 0x3f3f3f3f;
    int n;
    ll a[maxn];
    ll pre[maxn], tail[maxn], Max[maxn << 2];
    //1~i最多递增,i~n最多递增
    void build(int l, int r, int rt){
        if(l == r){
            Max[rt] = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
        Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]);
    }
    int tailMax, preMax;
    void queryPre(int l, int r, int L, int R, int rt){
        if(R == 0) return;
        if(l == r){
            if(a[l] > a[preMax]) preMax = l;
            return;
        }
        int m = (l + r) >> 1;
        if(L <= l && R >= r){
            if(Max[rt << 1] > Max[rt << 1 | 1])
                queryPre(l, m, L, R, rt << 1);
            else
                queryPre(m + 1, r, L, R, rt << 1 | 1);
            return;
        }
        if(L <= m)
            queryPre(l, m, L, R, rt << 1);
        if(R > m)
            queryPre(m + 1, r, L, R, rt << 1 | 1);
    }
    void queryTail(int l, int r, int L, int R, int rt, ll v){
        if(L == n + 1) return;
        if(l == r){
            if(Max[rt] > v) tailMax = min(l, tailMax);
            return;
        }
        int m = (l + r) >> 1;
        if(L <= l && R >= r){
            if(Max[rt << 1] > v){
                queryTail(l, m, L, R, rt << 1, v);
            }
            else if(Max[rt << 1 | 1] > v){
                queryTail(m + 1, r, L, R, rt << 1 | 1, v);
            }
            return;
        }
        if(Max[rt << 1] > v && L <= m){
            queryTail(l, m, L, R, rt << 1, v);
        }
        if(Max[rt << 1 | 1] > v && R > m){
            queryTail(m + 1, r, L, R, rt << 1 | 1, v);
        }
    }
    int main(){
        int m, T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n ,&m);
            ll u = 0;
            pre[0] = 0;
            a[0] = 0;
            for(int i = 1; i <= n; i++){
                scanf("%lld", &a[i]);
                if(a[i] > u){
                    u = a[i];
                    pre[i] = pre[i - 1] + 1;
                }
                else{
                    pre[i] = pre[i - 1];
                }
            }
            build(1, n, 1);
            for(int i = n; i >= 1; i--){
                tailMax = INF;
                queryTail(1, n, i + 1, n, 1, a[i]);
                if(tailMax == INF) tail[i] = 1;
                else tail[i] = 1 + tail[tailMax];
            }
            while(m--){
                int p;
                ll q;
                scanf("%d%lld", &p, &q);
                ll ans = 0;
                preMax = 0;
                queryPre(1, n, 1, p - 1, 1);
                ans += pre[preMax];
                if(q > a[preMax]){
                    ans += 1;
                }
                tailMax = INF;
                queryTail(1, n, p + 1, n, 1, max(a[preMax], q));
                if(tailMax != INF)  ans += tail[tailMax];
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    C#扩展方法学习
    如何用PS快速做出3D按钮效果的图片
    比较C#中几种常见的复制字节数组方法的效率[转]
    GUID的学习
    委托与事件的区别
    利用Marshal.AllocHGlobal申请非托管内存,unsafe代码
    JAVASE(十三) 异常处理
    JAVASE(十二) Java常用类: 包装类、String类、StringBuffer类、时间日期API、其他类
    JAVASE(十一) 高级类特性: abstract 、模板模式、interface、内部类、枚举、注解
    面试题: SpringBoot 的自启动原理
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9988228.html
Copyright © 2020-2023  润新知