zoukankan      html  css  js  c++  java
  • Wannafly Winter Camp Day8(Div1,onsite) E题 Souls-like Game 线段树 矩阵乘法

    (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

    Catalog

    @

    Problem:传送门

     Portal
     原题目描述在最下面。
     简单的说,每个点是一个矩阵,区间赋值和区间求积。

    Solution:

    (div2)版本就(O(n*m*9))暴力更新暴力矩阵乘法求答案就行了,代码挺短的,有需要的话去另一篇博客里有代码。
    在这里插入图片描述
    (div1)题解就上面这个,相信大家看完应该都能(ac)
    本题只有两种操作,区间赋值和区间求和(矩阵的积)。很自然就想到要用线段树优化咯,然后线段树每个节点都是一个矩阵。
    但是这题要先把区间长度扩展为2的幂次,为什么呢?因为:
    长度为(n)的区间长度有大概(log(n))种,但是当(n)不是(2)的幂次的时候,各种区间的长度是没有规律的。
    这题线段树每个节点维护的是矩阵信息,用(lazy)标记优化区间赋值时,其实就是求矩阵的(k)次幂。
    因为会有很多区间的长度相同,可以先把矩阵的k次幂预处理出来。
    而只有当总长度是2的幂次时,每个节点覆盖的区间长度都会是2的幂次。这样就解释完了。

    理解了这个,这题就随便写了。

    AC_Code:

    //哇,这题ac完感觉好爽啊
    //第一次写这种结构体线段树还重载操作符的,海星
    //没有人写博客,只能看着官方题解意会解法
    #include<bits/stdc++.h>
    #define clr(a, b) memset(a,b,sizeof((a)))
    #define lson rt<<1
    #define rson rt<<1|1
    using namespace std;
    typedef long long LL;
    
    const int MXN = 2e5 + 7;
    const LL mod = 998244353;
    
    int n, m, Q;
    int ar[MXN][3][3], two[33];
    int lazy[MXN<<2][3][3], flag[MXN<<2];
    map<int, int> mp;
    
    struct edge {
        int opt, l, r;
        int ar[3][3];
    }node[MXN];
    struct lp {
        int sum[3][3];
        friend lp operator *(const lp&a, const lp&b) {
            lp c;
            clr(c.sum, 0);
            for(int k = 0; k < 3; ++k) for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) {
                c.sum[i][j] = (c.sum[i][j]+(LL)a.sum[i][k]*b.sum[k][j])%mod;
            }
            return c;
        }
    }cw[MXN<<2], tp[MXN][33];
    
    void push_up(int rt) {
        cw[rt] = cw[lson] * cw[rson];
    }
    void build(int l,int r,int rt) {
        flag[rt] = -1;
        if(l == r) {
            for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) cw[rt].sum[i][j] = ar[l][i][j];
            return ;
        }
        int mid = (l + r) >> 1;
        build(l, mid, lson); build(mid+1,r,rson);
        push_up(rt);
    }
    void push_down(int l,int mid,int r,int rt) {
        if(flag[rt] == -1) return;
        flag[lson] = flag[rson] = flag[rt];
        for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) lazy[lson][i][j] = lazy[rt][i][j], lazy[rson][i][j] = lazy[rt][i][j];
        cw[lson] = tp[flag[rt]][mp[mid-l+1]-1];
        cw[rson] = tp[flag[rt]][mp[r-mid]-1];
        assert(mp[mid-l+1]); assert(mp[r-mid]);
        flag[rt] = -1;
    }
    void update(int L,int R,int id,int l,int r,int rt) {
        if(L <= l && r <= R) {
            flag[rt] = id;
            for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) lazy[rt][i][j] = node[id].ar[i][j];
            assert(mp[r-l+1]);
            cw[rt] = tp[id][mp[r-l+1]-1];
            return ;
        }
        int mid = (l + r) >> 1;
        push_down(l, mid, r, rt);
        if(L > mid) update(L, R, id, mid+1, r, rson);
        else if(R <= mid) update(L, R, id, l, mid, lson);
        else {
            update(L,mid,id,l,mid,lson); update(mid+1,R,id,mid+1,r,rson);
        }
        push_up(rt);
    }
    lp query(int L,int R,int l,int r,int rt) {
        if(L <= l && r <= R) {
            return cw[rt];
        }
        int mid = (l + r) >> 1;
        push_down(l, mid, r, rt);
        if(L > mid) return query(L, R, mid+1, r, rson);
        else if(R <= mid) return query(L, R, l, mid, lson);
        else {
            return query(L,mid,l,mid,lson)*query(mid+1,R,mid+1,r,rson);
        }
    }
    int main() {
        two[0] = 1, mp[1] = 1;
        for(int i = 1; i <= 17; ++i) two[i] = two[i-1] << 1, mp[1<<i] = i + 1;
        scanf("%d%d", &n, &Q);
        for(int i = 1; i < n; ++i) {
            for(int j = 0; j < 3; ++j) for(int k = 0; k < 3; ++k) scanf("%d", &ar[i][j][k]);
        }
        m = 2;
        while(m < n) m <<= 1;
        build(1, m, 1);
        int opt, l, r;
        for(int i = 1; i <= Q; ++i) {
            scanf("%d%d%d", &node[i].opt, &node[i].l, &node[i].r);
            if(node[i].opt == 1) {
                for(int k = 0; k < 3; ++k) for(int j = 0; j < 3; ++j) {
                    scanf("%d", &node[i].ar[k][j]);
                    tp[i][0].sum[k][j] = node[i].ar[k][j];
                }
                for(int k = 1; k <= 17; ++k) {
                    tp[i][k] = tp[i][k-1] * tp[i][k-1];
                }
                update(node[i].l, node[i].r, i, 1, m, 1);
            }else {
                LL ans = 0;
                lp a = query(node[i].l, node[i].r-1, 1, m, 1);
                for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) ans = (ans + a.sum[i][j]) % mod;
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
    

    Problem Description:

    在这里插入图片描述

  • 相关阅读:
    MYSQL利用merge存储引擎来实现分表
    IoC原理及实现
    prometheus + grafana安装部署(centos6.8)
    PHP Laravel定时任务Schedule
    排序算法杂谈(三) —— 归并排序的非递归实现
    排序算法杂谈(二) —— 冒泡排序的递归实现
    排序算法杂谈(一) —— 量化数组的有序程度
    排序算法(七) —— 快速排序
    排序算法(六) —— 归并排序
    排序算法(五) —— 堆排序
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/10347252.html
Copyright © 2011-2022 走看看