多校 1010 Taotao Picks Apples(补题)

》》点击进入原题《《

 思路:题解很有意思,适合线段树进阶 

考虑每次修改不叠加,因此我们可以从如何对原序列进行预处理着手。
通过观察可以发现,将原序列从任意位置断开,我们可以通过分别维护左右段的某些信息来拼接
得到答案。
对于左段来说:

• 需要知道最大值的位置,以及到达最大值需要几步;
• 使用 ST 维护信息。
对于右段来说:
• 由于前半部分的信息未知,因此我们需要维护从每个位置开始到结尾可以走几步;
• 从后往前做 DP,每次找出右边第一个比自己大的数,答案就是它的 DP 值 +1。
对于每次询问:
• 考虑这个数左边的部分加上这个数之后的答案和最大值;
• 再找到右边第一个大于左半部分最大值的数,答案相加即可。
预处理使用 ST 表,每次查询需要一个二分,总复杂度 O(nlogn+qlogn)。 —题解来自HDU

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define lson l,m,o<<1
#define rson m+1,r,o<<1|1

const int maxn = 1e5 + 10;
int a[maxn], d1[maxn], d2[maxn];
int tree[maxn << 2], vis[maxn << 2];
int ans, cur;

void build(int l, int r, int o){
    if (l == r){
        tree[o] = a[l];
        vis[o] = l;
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
    if (tree[o << 1] >= tree[o << 1 | 1])
        vis[o] = vis[o << 1];
    else vis[o] = vis[o << 1 | 1];

}
void query(int l, int r, int o, int ql, int qr, int k){
    if (l == r){
        if (tree[o]>k)
            cur = min(cur, l);
        return;
    }
    int m = (l + r) >> 1;
    if (l >= ql&&r <= qr){
        if (tree[o << 1] > k)
            query(lson, ql, qr, k);
        else if (tree[o << 1 | 1] > k)
            query(rson, ql, qr, k);
        return;
    }
    if (ql <= m)
        query(lson, ql, qr, k);
    if (qr > m)query(rson, ql, qr, k);
}
void query1(int l, int r, int o, int ql, int qr){
    if (l >= ql&&r <= qr){
        if (tree[o] > a[cur])
            cur = vis[o];
        return;
    }
    int m = (l + r) >> 1;
    if (ql <= m)query1(lson, ql, qr);
    if (qr > m)query1(rson, ql, qr);
}
int main(){
    ios::sync_with_stdio(false);

    int t; cin >> t;
    while (t--){
        int n, m, p, q, Max = 0;
        cin >> n >> m;
        for (int i = 1; i <= n; i++){
            cin >> a[i];
            if (a[i] > Max)
                d1[i] = d1[i - 1] + 1, Max = a[i];
            else d1[i] = d1[i - 1];
        }
        build(1, n, 1);
        for (int i = n; i; i--){
            cur = n + 1;
            query(1, n, 1, i, n, a[i]);
            if (cur > n)cur = 0;
            d2[i] = d2[cur] + 1;
        }
        while (m--){
            cin >> p >> q;
            ans = cur = 0;
            if (p != 1){
                query1(1, n, 1, 1, p - 1);
            }
            ans += d1[cur];
            if (q > a[cur])ans++;
            else q = a[cur];
            cur = n + 1;

            if (p != n)query(1, n, 1, p + 1, n, q);
            if (cur <= n)ans += d2[cur];
            cout << ans << endl;
        }
    }
}
原文地址:https://www.cnblogs.com/zengguoqiang/p/9506601.html