LOJ #573. 「LibreOJ NOI Round #2」单枪匹马 线段树
$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; }