习题:大魔法师(矩阵&线段树&卡常)
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;
}
以上是关于习题:大魔法师(矩阵&线段树&卡常)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3240 && 洛谷P1397矩阵游戏[NOI2013](矩阵乘法+卡常)
51nod 1206 && hdu 1828 Picture (扫描线+离散化+线段树 矩阵周长并)