习题:大魔法师(矩阵&线段树&卡常)

Posted loney-s

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了习题:大魔法师(矩阵&线段树&卡常)相关的知识,希望对你有一定的参考价值。

题目

传送门

思路

一道十分恶心的卡常毒瘤题目

关键是将操作转换成为一个矩阵的形式,

再用线段树来维护

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int mod=998244353;
void read(int &x)
{
    x=0;
    int f=1;
    char c=getchar();
    while('0'>c||c>'9')
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while('0'<=c&&c<='9')
    {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    }
    x*=f;
}
void write(int x)
{
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
struct matrix
{
    int n,m;
    int a[5][5];
    matrix()
    {
        n=0;
        m=0;
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)
                a[i][j]=0;
    }
    matrix operator * (const matrix &b)
    {
        matrix c;
        c.n=n;
        c.m=b.m;
        for(int i=1;i<=n;i++)
        {
            for(int k=1;k<=m;k++)
            {
                if(!a[i][k])
                    continue;
                for(int j=1;j<=b.m;j++)
                {
                    int t=1ll*a[i][k]*b.a[k][j]%mod;
                    c.a[i][j]+=t;
                    c.a[i][j]=c.a[i][j]>=mod?c.a[i][j]-mod:c.a[i][j];
                }
            }
        }
        return c;
    } 
    matrix operator + (const matrix &b)
    {
        matrix c;
        c.n=n;
        c.m=m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                c.a[i][j]=a[i][j]+b.a[i][j];
                c.a[i][j]=c.a[i][j]>=mod?c.a[i][j]-mod:c.a[i][j];
            }
        return c;
    }
};
struct tree
{
    int l;
    int r;
    matrix w;
    matrix lazy;
}tre[600005];
matrix meta;
matrix vec_meta;
matrix t;
matrix opt[8];
int n,m;
int optt,l,r,v;
void init()
{
    t.n=4;
    t.m=1;
    vec_meta.n=4;
    vec_meta.m=1;
    meta.n=4;
    meta.m=4;
    for(int i=1;i<=4;i++)
        meta.a[i][i]=1;
    opt[1]=meta;
    opt[1].a[1][2]=1;
    opt[2]=meta;
    opt[2].a[2][3]=1;
    opt[3]=meta;
    opt[3].a[3][1]=1;
    opt[4]=meta;
    opt[5]=meta;
    opt[6]=meta;
}
void build(int k,int l=1,int r=n)
{
    tre[k].l=l;
    tre[k].r=r;
    tre[k].lazy=meta;
    tre[k].w.n=4;
    tre[k].w.m=1;
    if(l==r)
    {
        for(int i=1;i<=3;i++)
            read(tre[k].w.a[i][1]);
        tre[k].w.a[4][1]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tre[k].w=tre[k<<1].w+tre[k<<1|1].w;
}
void push_down(int k)
{
    if(tre[k].l==tre[k].r)
        return;
    tre[k<<1].lazy=tre[k].lazy*tre[k<<1].lazy;
    tre[k<<1|1].lazy=tre[k].lazy*tre[k<<1|1].lazy;
    tre[k<<1].w=tre[k].lazy*tre[k<<1].w;
    tre[k<<1|1].w=tre[k].lazy*tre[k<<1|1].w;
    tre[k].lazy=meta;
}
void change(int k)
{
    if(tre[k].l>r||l>tre[k].r)
        return;
    if(l<=tre[k].l&&tre[k].r<=r)
    {
        tre[k].w=opt[optt]*tre[k].w;
        tre[k].lazy=opt[optt]*tre[k].lazy;
        return;
    }
    push_down(k);
    change(k<<1);
    change(k<<1|1);
    tre[k].w=tre[k<<1].w+tre[k<<1|1].w;
}
void ask(int k)
{
    if(tre[k].l>r||l>tre[k].r)
        return;
    if(l<=tre[k].l&&tre[k].r<=r)
    {
        t=t+tre[k].w;
        return;
    }
    push_down(k);
    ask(k<<1);
    ask(k<<1|1);
}
int main()
{
    init();
    read(n);
    build(1);
    read(m);
    for(int i=1;i<=m;i++)
    {
        read(optt);
        read(l);
        read(r);
        if(optt==7)
        {
            for(int i=1;i<=4;i++)
                for(int j=1;j<=1;j++)
                    t.a[i][j]=0;
            ask(1);
            write(t.a[1][1]);
            putchar(' ');
            write(t.a[2][1]);
            putchar(' ');
            write(t.a[3][1]);
            putchar('
');
            continue;
        }
        if(optt==4)
        {
            read(v);
            opt[4].a[1][4]=v;
        }
        if(optt==5)
        {
            read(v);
            opt[5].a[2][2]=v;
        }
        if(optt==6)
        {
            read(v);
            opt[6].a[3][3]=0;
            opt[6].a[3][4]=v;
        }
        change(1);
    }
    return 0;
}

以上是关于习题:大魔法师(矩阵&线段树&卡常)的主要内容,如果未能解决你的问题,请参考以下文章

矩阵线段树

洛谷3374

bzoj3240 && 洛谷P1397矩阵游戏[NOI2013](矩阵乘法+卡常)

51nod 1206 && hdu 1828 Picture (扫描线+离散化+线段树 矩阵周长并)

Rmp(Mex) & Destiny & 楼房重建(线段树上二分)

Codeforces 718C. Sasha and Array(线段树)