• Codeforces


    https://codeforc.es/contest/1199/problem/D

    其实后来想了一下貌似是个线段树的傻逼题。

    单调栈是这样思考的,每次单点修改打上一个最终修改的时间戳。每次全体修改就push进去单调栈。首先比新的全体修改的x小的(等的也)全部出栈,这样子单调栈里面就是一个递减的序列,而时间戳是递增的。

    最后对于每一个有修改标记的,在时间戳上面二分找到他的下一次修改,那么这个修改绝对就是足够大的。假如没有查找成功,则说明不存在最后一次修改。(可以通过在最后入栈一个0操作来统一),没有修改标记的那就直接赋值最大的全体修改。(相当于对0进行查询)

    其实也是nlogn的。常数估计更小。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    inline int read() {
        int x = 0;
        char c = getchar();
        for(; c < '0' || c > '9'; c = getchar());
        for(; c >= '0' && c <= '9'; c = getchar())
            x = (x << 3) + (x << 1) + c - '0';
        return x;
    }
    
    inline void _write(int x) {
        if(x > 9)
            _write(x / 10);
        putchar(x % 10 + '0');
    }
    
    inline void write(int x) {
        if(x < 0) {
            putchar('-');
            x = -x;
        }
        _write(x);
        putchar('
    ');
    }
    
    const int MAXN=200005;
    
    int n, q;
    int a[MAXN],lc[MAXN];
    int st1[MAXN],st2[MAXN],stop;
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        n = read();
        for(int i = 1; i <= n; ++i)
            a[i] = read();
    
        q = read();
        for(int qi = 1; qi <= q; qi++) {
            int op = read(), p, x;
            if(op == 1) {
                p = read(), x = read();
                a[p] = x;
                lc[p] = qi;
            } else {
                x = read();
                while(stop && st1[stop] <= x)
                    --stop;
                st1[++stop] = x;
                st2[stop] = qi;
            }
        }
        st1[++stop] = 0;
        st2[stop] = q + 1;
        for(int i = 1; i <= n; ++i)
            a[i] = max(a[i], st1[lower_bound(st2 + 1, st2 + 1 + stop, lc[i]) - st2]);
        for(int i = 1; i <= n; ++i)
            printf("%d%c", a[i], " 
    "[i == n]);
    }
    

    其实当时也在想,每次lazy更新2操作不就可以了吗?这样就直接是线段树。每次对点更新把一路上的lazy标记push下去,然后到叶子的时候把这个失效的lazy给清空了。query的时候记得要max上lazy,因为有一些叶子并没有被1操作对点更新但是lazy也确实传到这个叶子了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    const int MAXM = 200000;
    int a[MAXM + 5];
    int lazy[(MAXM << 2) + 5];
     
    inline void push_down(int o, int l, int r) {
        if(lazy[o]) {
            lazy[o << 1] = max(lazy[o << 1], lazy[o]);
            lazy[o << 1 | 1] = max(lazy[o << 1 | 1], lazy[o]);
            lazy[o] = 0;
        }
    }
     
    void update1(int o, int l, int r, int x, int v) {
        if(x <= l && r <= x) {
            lazy[o]=0;
            a[x] = v;
            return;
        } else {
            push_down(o, l, r);
            int m = (l + r) >> 1;
            if(x <= m)
                update1(o << 1, l, m, x, v);
            if(x >= m + 1)
                update1(o << 1 | 1, m + 1, r, x, v);
        }
    }
     
    void update2(int o, int l, int r, int v) {
        lazy[o] = max(lazy[o], v);
        return;
    }
     
    int query(int o, int l, int r, int x) {
        if(x <= l && r <= x) {
            return max(a[x], lazy[o]);
        } else {
            push_down(o, l, r);
            int m = (l + r) >> 1;
            if(x <= m)
                return query(o << 1, l, m, x);
            if(x >= m + 1)
                return query(o << 1 | 1, m + 1, r, x);
        }
    }
     
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
        //freopen("Yinku.out", "w", stdout);
    #endif // Yinku
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        int q;
        scanf("%d", &q);
        for(int i = 1; i <= q; ++i) {
            int op;
            scanf("%d", &op);
            if(op == 1) {
                int x, v;
                scanf("%d%d", &x, &v);
                update1(1, 1, n, x, v);
            } else {
                int x;
                scanf("%d", &x);
                update2(1, 1, n, x);
            }
        }
        for(int i = 1; i <= n; ++i) {
            a[i] = query(1, 1, n, i);
            printf("%d%c", a[i], " 
    "[i == n]);
        }
    }
    
  • 相关阅读:
    oracle 例外
    Help with Intervals(集合的交并补,线段树)
    Mex(线段树的巧妙应用)
    hdu4578Transformation(线段树多个lz标记)
    Coder(线段树)
    Ice-cream Tycoon9(线段树)
    Partition(线段树的离线处理)
    ACM学习大纲(转)
    Codeforces Round #250 (Div. 1)
    记次浙大月赛 134
  • 原文地址:https://www.cnblogs.com/Yinku/p/11275436.html
Copyright © 2020-2023  润新知