0
点赞
收藏
分享

微信扫一扫

小米14 ULTRA:重新定义手机摄影的新篇章

登录—专业IT笔试面试备考平台_牛客网

using i64 = long long;
using ll = long long;
constexpr ll M = 1e9 + 7;
template<class Info>
struct SegmentTree {
    int n;
    std::vector<Info> info;
    SegmentTree() : n(0) {}
    SegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    SegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector<Info>(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << (int)std::log2(n), Info());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void modify(int p, int l, int r, int x, const Info& v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        }
        else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info& v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};

struct Info {
    ll a;//表示黄色砖块,当前
    ll b;
    ll c = 1;
    ll d;
};

Info operator+(const Info& b, const Info& a) {
    //b.a + a.a * b.c
    //b.b + a.a * b.d + a.b 
    //a.c * b.c
    //a.c * b.d + a.d 
    
    return { (b.a + ((a.a%M) * (b.c%M))%M)%M, (b.b + ((a.a%M) * (b.d%M)) + a.b)%M, ((a.c%M) * (b.c%M))%M, (((a.c%M) * (b.d%M)%M) + a.d)%M };
}

Info Y{ 0, 0, 1, 1 };
Info B{ 1, 0, 0, 1 };//箭头指向下一个位置
Info R{ 0, 0, 2, 1 };//总数量乘以2在加上一个红色砖块

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, q;
    std::cin >> n >> q;

    std::string s;
    std::cin >> s;
    //最底层的n个区间,比如[0,1)表示第一个区间,代表第一块砖
    SegmentTree<Info> seg(n);
    for (int i = 0; i < n; i++) {
        seg.modify(i, (s[i] == 'Y') ? Y : ((s[i] == 'B') ? B : R));
        /*for (int j = 0; j < n; j++) {
            Info t = seg.rangeQuery(j, j + 1);
            std::cout <<j<<":"<< t.a << ' ' << t.b << ' ' << t.c << ' ' << t.d << '\n';
        }*/
    }

    while (q--) {
        int o;
        std::cin >> o;

        if (o == 1) {
            int p;
            char c;
            std::cin >> p >> c;
            p--;
            seg.modify(p, (c == 'Y') ? Y : ((c == 'B') ? B : R));
        }
        else {
            int l, r;
            std::cin >> l >> r;
            l--;
            Info res = seg.rangeQuery(l, r);
            //b和d的和为总数
            ll ans = (res.b + res.d) % M;
            std::cout << ans << "\n";
        }
    }

    return 0;
}

第一点:std::vector<Info> info;存的是按区间字符操作后的效果,有点难理解,举个例子,如果你查询[0,1)这个区间相当于查询按第一个字符进行游戏后的效果,如果第一个字符是Y,那么查询的结果就是Info Y{ 0, 0, 1, 1 };至于Info为什么要这么定义我们来看看下面的内容.

其中最难理解的就是下面这一部分

struct Info {
    ll a;//最左边的柱子的倍数
    ll b;//所有累计的方块
    ll c = 1;//现有倍数
    ll d;//现有这一列的方块
};

Info operator+(const Info& b, const Info& a) {
    //b.a + a.a * b.c
    //b.b + a.a * b.d + a.b
    //a.c * b.c
    //a.c * b.d + a.d 
    
    return { (b.a + ((a.a%M) * (b.c%M))%M)%M, (b.b + ((a.a%M) * (b.d%M)) + a.b)%M, ((a.c%M) * (b.c%M))%M, (((a.c%M) * (b.d%M)%M) + a.d)%M };
}

Info Y{ 0, 0, 1, 1 };
Info B{ 1, 0, 0, 1 };//箭头指向下一个位置
Info R{ 0, 0, 2, 1 };//总数量乘以2在加上一个红色砖块

首先a,b,c,d的意思我都标出来了,为什么要这么定义呢,我们这样想,当中间有很多个操作B出现的时候,那么这个区间是不是有很多个柱子,这样不清楚,让我来画个图

如果产生了多个柱子是不是说明有操作B,第一个柱子不管是YRRY或是什么其它的操作它都不可能产生第二个柱子.假如我们要合并两个区间,

每根柱子表示的无非就是YR的组合,可能是YYYY,RRRR又或者是YRRY等等,不存在B所以最后一根和第一根合并的序列一定是一根,那么效果是怎样的呢, 显然最后一根总方块数我们可以设为k,那么合并后可以表示为((k+a1)*2+a2)*2+a3,原先第一根的方块数为(a1*2+a2)*2+a3,两者的差值不就是把k提到外面来吗及(a1*2+a2)*2+a3+4*k(注意,我只是举了一个只有两个R情况下的例子,*2的数量要根据R的数量来定),那么+重载为什么这样运算也很明显了.

对于第一个算式b.a + a.a * b.c,再使用B之前,第一根的方块数量和R的数量是不确定的,如果第一个区间有B,那么第一个区间的c变量是0,也就是说两个区间合并后的第一根倍数就是b.a,如果第一个区间没有B,说明第二个区间的第一根和第一个区间合并后会变成一根,即b.c不为0而b.a为0,合并后的第一根是a.a乘以b.c.

感觉解释的不是很清楚(*/ω\*),换个解释方法,Info Y{ 0, 0, 1, 1 };第一个1表示当前倍数为自己身的一倍,也就是不翻倍,第二个1表示添加到目前这根柱子里添加一个方块,Info R{ 0, 0, 2, 1 };翻倍后添加,Info B{ 1, 0, 0, 1 };这涉及到好几个运算,首先看最简单的a.c*b.c表示第一根柱子已经固定了,根据之前讲的最后一根和第一根合并的运算,我们要把当前倍数转移到a变量里,及a.a * b.c,因为b是左边的区间,所以按照这个运算,如果它在之前有过B字符,那么它也不为0,所以要加上b.a.

列举了两个,其它的是一样的,就像是自动机一样,涉及到有B和没B的情况,比较难解释,当涉及B的时候某些变量会自动变为0从而做出变换.

b.a(有B/没B) + a.a(有B/没B) * b.c(没B/有B)
b.b(有B/没B) + a.a(有B/没B) * b.d + a.b(有B/没B)         有Ba.a会把b.d添加到非当前柱子
a.c * b.c(没B/有B)
a.c(没B/有B) * b.d + a.d        没有B的时候a.c会把b.d添加到当前柱子 

大概就是这样,尽力了,很难解释.

举报

相关推荐

0 条评论