1. 程式人生 > >luogu4891序列 線段樹

luogu4891序列 線段樹

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;
}