Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树

Posted kaka0010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树相关的知识,希望对你有一定的参考价值。

原题链接:https://codeforces.ml/contest/1567/problem/E

题意

有一个a序列,接下来会有两个操作

  1. x y 将 a x a_x ax改为y
  2. l r 查询 [ l , r ] [l,r] [l,r]区间内有多少p,q满足l<=p<=q<=r且 [ a p , a p + 1 . . a q ] [a_p,a_{p+1}..a_{q}] [ap,ap+1..aq]为不递减序列

分析

当我们知道一个区间大小为len时,那么满足条件的p,q对数为 l e n ∗ ( l e n + 1 ) / 2 len*(len+1)/2 len(len+1)/2,这个结论是显而易见的,因此直接丢在线段树上维护。

怎么维护呢,我们参考线段树维护最大连续区间和的方法。
记录lsum,rsum分别表示从左到右和从右到左连续长度是多少,记录lnum和rnum表示最左端和最右端的值是多少,记录sum为总区间个数。

首先我们在push_up的时候考虑左右区间的贡献,发现只有在中间部分连续时即p,q横跨mid时才会产生多余的贡献,那么我们先加上左右区间的贡献,然后减去响应连续段的贡献,最后加上合并后的贡献。具体实现可以看代码。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<int, int> PII;
const ll inf = 2e18;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;

#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\\n'

struct node {
    int l, r;
    int lsum, rsum;
    int lnum, rnum;
    ll sum;
}t[N<<2];
int a[N];
ll getsum(ll n) {
    return n * (n + 1) / 2;
}
void push_up(node &now, node &L, node &R) {
    int len1 = L.r-L.l+1, len2 = R.r-R.l+1;
    now.sum = L.sum + R.sum;
    now.lnum = L.lnum;
    now.rnum = R.rnum;
    now.lsum = L.lsum;
    now.rsum = R.rsum;
    if (L.lsum == len1 && L.rnum <= R.lnum) now.lsum += R.lsum;
    if (R.rsum == len2 && L.rnum <= R.lnum) now.rsum += L.rsum;
    if (L.rnum <= R.lnum) {
        now.sum -= getsum(L.rsum);
        now.sum -= getsum(R.lsum);
        now.sum += getsum(L.rsum + R.lsum);
    }
}
void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r;
    if (l == r) {
        t[u].lnum = t[u].rnum = a[l];
        t[u].lsum = t[u].rsum = 1;
        t[u].sum = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid+1, r);
    push_up(t[u], t[u<<1], t[u<<1|1]);
}
void modify(int u, int pos, int val) {
    if (t[u].l == t[u].r) {
        t[u].lnum = t[u].rnum = val;
        return;
    }
    int mid = (t[u].l + t[u].r) >> 1;
    if (pos <= mid) modify(u<<1, pos, val);
    else modify(u<<1|1, pos, val);
    push_up(t[u], t[u<<1], t[u<<1|1]);
}
node query(int u, int ql, int qr) {
    if (ql <= t[u].l && qr >= t[u].r) return t[u];
    int mid = (t[u].l + t[u].r) >> 1;
    if (qr <= mid) return query(u<<1, ql, qr);
    else if (ql > mid) return query(u<<1|1, ql, qr);
    else {
        node L = query(u<<1, ql, qr);
        node R = query(u<<1|1, ql, qr);
        node res;
        push_up(res, L, R);
        return res;
    }
}
inline void solve() {
    int n, q; cin >> n >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    while (q--) {
        int opt, x, y; cin >> opt >> x >> y;
        if (opt == 1) {
            modify(1, x, y);
        } else {
            printf("%lld\\n", query(1, x, y).sum);
        }
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}

以上是关于Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #742 div.2 A-F题解

Codeforces Round #742 div.2 A-F题解

Codeforces Round #742 (Div. 2)A-E

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma 线段树

Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)