zoukankan      html  css  js  c++  java
  • luoguP2572 [SCOI2010]序列操作

    非常简单的一道线段树题

    然而在考场上遇见还是打了$40min$,果然$gedit$不太适合我啊....

    维护区间左端,右端,内部最长连续$0/ 1$,以及区间内$0 / 1$的个数即可回答

    复杂度$O(n log n)$

    注:讨论线段树标记下放顺序的时候,一定要有组样例,脑想特别容易错!

    注2:反转标记和覆盖标记没有绝对明显的顺序,可以根据实现决定谁先下放

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;    
    }
    
    #define ri register int
    #define sid 600050
    
    int n, m;
    int w[sid];
    struct Seg {
        int lmax[2], rmax[2], max[2], num[2];
        int rev, cov, len;
    } t[sid];
    
    #define ls (o << 1)
    #define rs (o << 1 | 1)
    
    void pcov(int o, int v) {
        t[o].lmax[v] = t[o].rmax[v] = t[o].max[v] = t[o].num[v] = t[o].len;
        t[o].rev = 0; t[o].cov = v; v ^= 1;
        t[o].lmax[v] = t[o].rmax[v] = t[o].max[v] = t[o].num[v] = 0;
    }
    
    void prev(int o) {
        t[o].rev ^= 1;
        swap(t[o].lmax[1], t[o].lmax[0]); swap(t[o].rmax[1], t[o].rmax[0]);
        swap(t[o].max[1], t[o].max[0]); swap(t[o].num[1], t[o].num[0]);
    }
    
    void pud(int o) {
        if(t[o].cov != -1) { pcov(ls, t[o].cov); pcov(rs, t[o].cov); t[o].cov = -1; }    
        if(t[o].rev) { prev(ls); prev(rs); t[o].rev = 0; }
    }
    
    void upd(int o) {
        for(ri i = 0; i <= 1; i ++) {
            t[o].lmax[i] = t[ls].lmax[i];
            if(t[ls].num[i] == t[ls].len) t[o].lmax[i] = t[rs].lmax[i] + t[ls].len;
            t[o].rmax[i] = t[rs].rmax[i];
            if(t[rs].num[i] == t[rs].len) t[o].rmax[i] = t[ls].rmax[i] + t[rs].len;
            t[o].max[i] = max(t[ls].rmax[i] + t[rs].lmax[i], max(t[rs].max[i], t[ls].max[i]));
            t[o].num[i] = t[ls].num[i] + t[rs].num[i];
        }
    }
    
    void Init_Seg(int o, int l, int r) {
        t[o].len = r - l + 1; t[o].cov = -1;
        if(l == r) {
            int v = w[l];
            t[o].lmax[v] = t[o].rmax[v] = 1;
            t[o].max[v] = t[o].num[v] = 1;
            return;
        }
        int mid = (l + r) >> 1;
        Init_Seg(ls, l, mid);
        Init_Seg(rs, mid + 1, r);
        upd(o);
    }
    
    void Cov(int o, int l, int r, int ml, int mr, int v) {
        if(ml > r || mr < l) return;
        if(ml <= l && mr >= r) { pcov(o, v); return; }
        pud(o); 
        int mid = (l + r) >> 1;
        Cov(ls, l, mid, ml, mr, v);
        Cov(rs, mid + 1, r, ml, mr, v);
        upd(o);
    }
    
    void Rev(int o, int l, int r, int ml, int mr) {
        if(ml > r || mr < l) return;
        if(ml <= l && mr >= r) { prev(o); return; }
        pud(o); 
        int mid = (l + r) >> 1;
        Rev(ls, l, mid, ml, mr);
        Rev(rs, mid + 1, r, ml, mr);
        upd(o); 
    }
    
    int Sum(int o, int l, int r, int ml, int mr) {
        if(ml > r || mr < l) return 0;
        if(ml <= l && mr >= r) return t[o].num[1];
        pud(o);
        int mid = (l + r) >> 1; 
        return Sum(ls, l, mid, ml, mr) + Sum(rs, mid + 1, r, ml, mr);
    }
    
    int pre, ans;
    
    void Max(int o, int l, int r, int ml, int mr) {
        if(ml > r || mr < l) return;
        if(ml <= l && mr >= r) {
            ans = max(ans, t[o].max[1]);
            ans = max(ans, pre + t[o].lmax[1]);
            if(t[o].num[1] == t[o].len) pre += t[o].len;
            else pre = t[o].rmax[1];
            return;
        }
        pud(o);
        int mid = (l + r) >> 1;
        Max(ls, l, mid, ml, mr);
        Max(rs, mid + 1, r, ml, mr);
    }
    
    int main() {
        n = read(); m = read();
        for(ri i = 1; i <= n; i ++) w[i] = read();
        Init_Seg(1, 1, n);
        for(ri i = 1; i <= m; i ++) {
            int opt = read(), l = read() + 1, r = read() + 1;
            if(opt == 0) Cov(1, 1, n, l, r, 0);
            if(opt == 1) Cov(1, 1, n, l, r, 1);
            if(opt == 2) Rev(1, 1, n, l, r);
            if(opt == 3) printf("%d
    ", Sum(1, 1, n, l, r));
            if(opt == 4) pre = 0, ans = 0, Max(1, 1, n, l, r), printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    常用dos命令
    反射
    干货|技术小白如何在45分钟内发行通证(TOKEN)并上线交易(附流程代码
    基于以太坊发布属于自己的数字货币(代币)完整版
    基于以太坊实现代币发布
    FTRL的理解
    FM-分解机模型详解
    深度学习总结
    DIN
    git上传新项目
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9533153.html
Copyright © 2011-2022 走看看