Souls-like Game
直接线段树合并矩阵会被卡T掉,因为修改的复杂度比询问的复杂度多一个log,所以我们考虑优化修改。
修改的瓶颈在于打lazy的时候, 所以我们预处理出每个修改矩阵2的幂次,然后直接更新。
//#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize(4) //#pragma GCC optimize("unroll-loops") //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack-protector") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include<bits/stdc++.h> #define fi first #define se second #define db double #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define vi vector<int> #define mod 998244353 #define ld long double //#define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pll pair<ll,ll> #define pil pair<int,ll> #define pli pair<ll,int> #define pii pair<int,int> #define ull unsigned long long //#define base 1000000000000000000 #define fin freopen("a.txt","r",stdin) #define fout freopen("a.txt","w",stdout) #define fio ios::sync_with_stdio(false);cin.tie(0) inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;} inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;} template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;} template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;} inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;} inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;} using namespace std; const ull ba=233; const db eps=1e-9; const ll INF=0x3f3f3f3f3f3f3f3f; const int N = 200000+10,maxn=4000000+10,inf=0x3f3f3f3f; int nn, tot; struct Matrix { int a[3][3]; Matrix() { memset(a, 0, sizeof(a)); } void read() { for(int i=0;i<3;i++)for(int j=0;j<3;j++)scanf("%d",&a[i][j]); } void pr() { for(int i=0;i<3;i++) { for(int j=0;j<3;j++)printf("%d ",a[i][j]); puts(""); } } void init() { for(int i = 0; i < 3; i++) a[i][i] = 1; } Matrix operator * (const Matrix &B) const { Matrix C; for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 3; k++) C.a[i][j] = (C.a[i][j] + 1ll * a[i][k] * B.a[k][j]) % mod; return C; } Matrix operator ^ (int b) { Matrix C; C.init(); Matrix A = (*this); while(b) { if(b & 1) C = C * A; A = A * A; b >>= 1; } return C; } } o[N<<2], tmp[N][20]; int lazy[N<<2], depth[N<<2], cnt; bool ok[N<<2]; void pushup(int rt){o[rt]=o[rt<<1]*o[rt<<1|1];} void pushdown(int l,int r,int rt) { if(!ok[rt]) return; int m=(l+r)>>1; o[rt<<1]=tmp[lazy[rt]][depth[rt<<1]]; o[rt<<1|1]=tmp[lazy[rt]][depth[rt<<1|1]]; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; ok[rt<<1] = ok[rt<<1|1] = true; ok[rt] = false; } void build(int l,int r,int rt,int deep) { depth[rt] = deep; ok[rt] = false; if(l==r){if(l <= nn) o[rt].read();return;} int m=(l+r)>>1; build(ls, deep-1);build(rs, deep-1); pushup(rt); } void update(int L,int R,int who,int l,int r,int rt) { if(L<=l&&r<=R) { o[rt] = tmp[who][depth[rt]]; lazy[rt] = who; ok[rt] = true; return; } pushdown(l,r,rt); int m=(l+r)>>1; if(L<=m)update(L,R,who,ls); if(m<R)update(L,R,who,rs); pushup(rt); } Matrix query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return o[rt]; } pushdown(l,r,rt); int m=(l+r)>>1; Matrix te;te.init(); if(L<=m)te=te*query(L,R,ls); if(m<R)te=te*query(L,R,rs); return te; } int main() { int n, m, p; scanf("%d%d",&n,&m);n--; nn = n; for(p = 0; (1 << p) < n; p++); n = 1 << p; build(1, n, 1, p); while(m--) { int op,l,r;scanf("%d%d%d",&op,&l,&r); if(op==1) { cnt++; tmp[cnt][0].read(); for(int i = 1; i < 20; i++) tmp[cnt][i] = tmp[cnt][i - 1] * tmp[cnt][i - 1]; update(l,r,cnt,1,n,1); } else { --r; Matrix te=query(l,r,1,n,1); ll ans=0; for(int i=0;i<3;i++)for(int j=0;j<3;j++)add(ans,1ll*te.a[i][j]); printf("%lld\n",ans); } } return 0; } /* */