$f$ 函数暴力计算的话是 $O(n)$ 的(用一个 $\frac{x}{y}$ 来保存每一步计算结果,然后依次合并)
我们将一段区间的结果写成 $\frac{ax+by}{cx+dy}$ 的形式,初始时 $(x=0,y=1)$,然后这样的话就可以将区间分治,然后左右区间合并了.
注意合并的时候要把右区间的分子和分母调换一下.
code:
#include <bits/stdc++.h>
#define N 1000007
#define mod 998244353
#define ll long long
#define lson now<<1
#define rson now<<1|1
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;}
struct data
{
ll a,b,c,d;
data(int v=0) { a=1,b=v,c=0,d=1; }
data operator+(const data pp) const
{
data nw;
data p=pp;
swap(p.a,p.c),swap(p.b,p.d);
nw.a=(a*p.a+b*p.c)%mod;
nw.b=(a*p.b+b*p.d)%mod;
nw.c=(c*p.a+d*p.c)%mod;
nw.d=(c*p.b+d*p.d)%mod;
return nw;
}
}s[N<<2];
void update(int l,int r,int now,int p,int v)
{
if(l==r)
{
s[now]=data(v);
return;
}
int mid=(l+r)>>1;
if(p<=mid) update(l,mid,lson,p,v);
else update(mid+1,r,rson,p,v);
s[now]=s[lson]+s[rson];
}
data query(int l,int r,int now,int L,int R)
{
if(l>=L&&r<=R) return s[now];
int mid=(l+r)>>1;
if(L<=mid&&R>mid)
return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R);
else if(L<=mid) return query(l,mid,lson,L,R);
else return query(mid+1,r,rson,L,R);
}
void build(int l,int r,int now)
{
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[now]=s[lson]+s[rson];
}
int main()
{
// setIO("input");
int k,m,ty,n;
k=rd(),m=rd(),ty=rd();
n=k+m;
build(1,n,1);
for(int i=1;i<=k;++i)
{
int x=rd();
update(1,n,1,i,x);
}
int ansx=0,ansy=0;
for(int i=1;i<=m;++i)
{
int op=rd(),x,l,r;
if(op==1)
{
x=rd();
if(ty==1) x^=(ansx^ansy);
++k,update(1,n,1,k,x);
}
else
{
l=rd(),r=rd();
if(ty==1) l^=(ansx^ansy);
if(ty==1) r^=(ansx^ansy);
data p=query(1,n,1,l,r);
ansx=p.b,ansy=p.d;
printf("%d %d\n",ansx,ansy);
}
}
return 0;
}