luogu4891序列 线段树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/83591323

luoguP4891 序列

题目传送门

分析

神仙线段树。
被各种优美的暴力吊打。
首先 B B 数组的修改操作显然是可以暴力的,因为一旦取到了 B B ,由于修改操作是单调的, A A 的修改肯定不会再影响到这个取到的 B B
其次是 A A 的修改,线段树中维护 C C ,这样的话再线段树上二分之后相当于是区间赋值操作。
分析一波之后的核心就是要如何保证改修改的修改,不该修改的不修改。

维护的值

有些取 C C ,有些取 B B ,所以干脆维护 C C B B 的乘积(分开维护)。
既然维护的是 C C ,那么肯定要维护 C C 的值。
再考虑 B B 的暴力。如果某次 C C 的值修改得比 B B 的大,那么要去暴力找到那个需要取到最小值的 B B ,所以维护 B B 的最小值,如果需要修改就暴力进入那个区间。
最后由于区间赋值操作,所以肯定要有一个 t a g tag
由于需要计算赋值时候的乘积,所以需要维护一个 c n t cnt 表示
取到 C C 的个数。
操作的时候大力分类+维护即可。
复杂度 O ( n l o g 2 n ) O(nlog^2n) ,因为赋值的时候要快速幂

代码

指针真好玩~

#include<bits/stdc++.h>
const int N = 1e5 + 10, P = 1e9 + 7, inf = 1e9;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int a[N], b[N];
int Pow(int x, int k) {
    int r = 1;
    for(;k; x = 1LL * x * x % P, k >>= 1) if(k & 1) r = 1LL * r * x % P;
    return r;
}
struct Node {
    int ma, mb, ta, tb, cnt; bool tag; Node *ls, *rs;
    void Init(int A, int B) {
        ma = A; mb = B;
        (cnt = A < B) ? ta = A, tb = 1 : (tb = B, mb = inf, ta = 1);
    }
    void Tag(int v) {ma = v; ta = Pow(v, cnt); tag = true;}
    void Dw() {if(tag) ls->Tag(ma), rs->Tag(ma), tag = false;}
    void Up() {
        ma = std::max(ls->ma, rs->ma);
        mb = std::min(ls->mb, rs->mb);
        ta = 1LL * ls->ta * rs->ta % P;
        tb = 1LL * ls->tb * rs->tb % P;
        cnt = ls->cnt + rs->cnt;
    }
    void Build(int L, int R) {
        if(L == R) {
            ma = a[L]; mb = b[L];
            (cnt = a[L] < b[L]) ? (ta = ma, tb = 1) : (tb = mb, mb = inf, ta = 1);
            return ;
        }
        int m = L + R >> 1;
        (ls = new Node)->Build(L, m);
        (rs = new Node)->Build(m + 1, R);
        Up();
    }
    void UpB(int L, int R, int v, int w) {
        if(L == R) return Init(ma, w);
        Dw(); int m = L + R >> 1;
        v <= m ? ls->UpB(L, m, v, w) : rs->UpB(m + 1, R, v, w);
        Up();
    }
    void UpA(int L, int R, int w) {
        if(w < mb) return Tag(w);
        if(L == R) return Init(w, mb);
        Dw(); int m = L + R >> 1;
        ls->UpA(L, m, w); rs->UpA(m + 1, R, w);
        Up();
    }
    void Bound(int L, int R, int v, int w) {
        if(v == L && ma < w) return UpA(L, R, w);
        if(L == R) return ;
        Dw(); int m = L + R >> 1;
        if(v > m) return rs->Bound(m + 1, R, v, w), Up();
        if(ls->ma < w) rs->Bound(m + 1, R, m + 1, w);
        ls->Bound(L, m, v, w);
        Up();
    }
}rt;
int main() {
    int n = ri(), q = ri();
    for(int i = 1;i <= n; ++i) a[i] = std::max(a[i - 1], ri());
    for(int i = 1;i <= n; ++i) b[i] = ri();
    rt.Build(1, n);
    for(;q--;) {
        int op = ri(), x = ri(), y = ri();
        op ? rt.UpB(1, n, x, y) : rt.Bound(1, n, x, y);
        printf("%d\n", 1LL * rt.ta * rt.tb % P);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/83591323
今日推荐