题解 Omeed

传送门

差了一点没想到正解……

首先单次询问的 \(O(n)\) 写法很好想,考虑如何优化
首先基础分区间求和即可
然后那个连击分的话,是一个关于 \(f_i\) 和 \(f_{i-1}\) 的柿子

\[f_i = p*(f_{i-1}+1)+(1-p)*f_{i-1}*t \]

移个项

\[f_i = (p+t-p*t)f_{i-1}+p \]

就表示成了一个 \(f_i = k_i*f_{i-1}+b_i\) 的形式

  • 形似 \(f_i = k_i*f_{i-1}+b_i\) 的柿子可以用线段树维护,核心在于维护出每个区间 \(R\) 位置相对 \(L-1\) 位置的 \(k\) 和 \(b\)

于是发现我们要求的 \(\sum p_i(f_{i-1}+1)\) 本来就是一个 \(kx+b\) 的形式
直接维护就好了

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
#define reg register int
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, q, sub;
int ta, tb, A, B, t, pa, pb;
int p[N], c[N];
const ll mod=998244353;
const int mod2=998244353;
inline void md(int& a, ll b) {a+=b; a=a>=mod2?a-mod2:a;}
inline int md(int a) {return a>=mod2?a-mod2:a;}
struct equ{int k, b, sumk, sumb; equ(){} equ(int e, int f, int g, int h):k(e),b(f),sumk(g),sumb(h){}};
inline equ operator + (equ a, equ b) {
	equ ans;
	ans.k=1ll*a.k*b.k%mod;
	ans.b=(1ll*b.k*a.b+b.b)%mod;
	ans.sumk=(a.sumk+1ll*b.sumk*a.k)%mod;
	ans.sumb=(a.sumb+1ll*b.sumk*a.b+b.sumb)%mod;
	return ans;
}
int tl[N<<2], tr[N<<2], sum[N<<2]; equ sk[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define sum(p) sum[p]
#define sk(p) sk[p]
#define k(p) sk[p].k
#define b(p) sk[p].b
#define sumk(p) sk[p].sumk
#define sumb(p) sk[p].sumb
inline void pushup(int p) {
	sum(p)=md(sum(p<<1)+sum(p<<1|1));
	sk(p)=sk(p<<1)+sk(p<<1|1);
}
void build(int tp, int l, int r) {
	tl(tp)=l; tr(tp)=r;
	if (l==r) {sum(tp)=p[l]; k(tp)=(p[l]+t-1ll*p[l]*t)%mod; b(tp)=sumk(tp)=sumb(tp)=p[l]; return ;}
	int mid=(tl(tp)+tr(tp))>>1;
	build(tp<<1, l, mid);
	build(tp<<1|1, mid+1, r);
	pushup(tp);
}
void upd(int p, int pos, int dat) {
	if (tl(p)==tr(p)) {sum(p)=dat; k(p)=(dat+t-1ll*dat*t)%mod; b(p)=sumk(p)=sumb(p)=dat; return ;}
	int mid=(tl(p)+tr(p))>>1;
	if (pos<=mid) upd(p<<1, pos, dat);
	else upd(p<<1|1, pos, dat);
	pushup(p);
}
int queryA(int p, int l, int r) {
	if (l<=tl(p) && r>=tr(p)) return sum(p);
	int mid=(tl(p)+tr(p))>>1, ans=0;
	if (l<=mid) md(ans, queryA(p<<1, l, r));
	if (r>mid) md(ans, queryA(p<<1|1, l, r));
	return ans;
}
equ query(int p, int l, int r) {
	if (l<=tl(p) && r>=tr(p)) return sk(p);
	int mid=(tl(p)+tr(p))>>1;
	if (l<=mid && r>mid) return query(p<<1, l, r)+query(p<<1|1, l, r);
	if (l<=mid) return query(p<<1, l, r);
	if (r>mid) return query(p<<1|1, l, r);
	puts("error");
	return sk(p);
}
int queryA(int l, int r) {
	int tem=1ll*A*queryA(1, l, r)%mod;
	return md(tem+mod);
}

ll qpow(ll a, ll b) {
	ll ans=1;
	while (b) {
		if (b&1) ans=ans*a%mod;
		a=a*a%mod; b>>=1;
	}
	return ans;
}

#if 0
namespace force{
	ll query(int l, int r) {
		ll base=0, com=0;
		for (int i=l; i<=r; ++i) md(base, p[i]);
		base=base*A%mod;
		c[l]=p[l]; md(com, p[l]%mod);
		for (int i=l+1; i<=r; ++i) {
			c[i]=(p[i]*(c[i-1]+1)%mod + (1-p[i])*c[i-1]%mod*t%mod)%mod;
			c[i]=(c[i]%mod+mod)%mod;
			md(com, p[i]*(c[i-1]+1)%mod);
		}
		ll tem=(base+com*B%mod)%mod;
		//assert(tem>=0);
		return (tem+mod)%mod;
	}
	void solve() {
		for (int i=1,op,l,r,x; i<=q; ++i) {
			op=read();
			if (op&1) {
				l=read(); r=read();
				printf("%lld\n", query(l, r));
			}
			else {
				x=read(); pa=read(); pb=read();
				p[x]=pa*qpow(pb, mod-2)%mod;
			}
		}
		exit(0);
	}
}

namespace task1{
	void solve() {
		build(1, 1, n);
		for (int i=1; i<=n; ++i) upd(1, i, p[i]);
		for (int i=1,op,l,r,x; i<=q; ++i) {
			op=read();
			if (op&1) {
				l=read(); r=read();
				printf("%lld\n", queryA(l, r));
			}
			else {
				x=read(); pa=read(); pb=read();
				p[x]=pa*qpow(pb, mod-2)%mod;
				upd(1, x, p[x]);
			}
		}
		exit(0);
	}
}
#endif

namespace task{
	void solve() {
		build(1, 1, n);
		equ tem;
		for (reg i=1,op,l,r,x; i<=q; ++i) {
			op=read();
			if (op&1) {
				l=read(); r=read();
				//cout<<"op=1"<<endl;
				if (l==r) printf("%lld\n", (p[l]*A+p[l]*B)%mod);
				else {
					tem=query(1, l+1, r);
					ll ans=(1ll*p[l]*tem.sumk+tem.sumb+p[l])%mod*B+queryA(l, r);
					ans = md(ans%mod+mod);
					printf("%lld\n", ans);
				}
			} 
			else {
				x=read(); pa=read(); pb=read();
				p[x]=pa*qpow(pb, mod-2)%mod;
				upd(1, x, p[x]);
			}
		}
		exit(0);
	}
}

signed main()
{
	sub=read();
	n=read(); q=read(); ta=read(); tb=read(); A=read(); B=read();
	if (!q) return 0;
	t=ta*qpow(tb, mod-2)%mod;
	for (reg i=1; i<=n; ++i) {
		pa=read(); pb=read();
		p[i]=pa*qpow(pb, mod-2)%mod;
	}
	//if (!B) task1::solve();
	//else force::solve();
	task::solve();
	
	return 0;
}
上一篇:数据仓库分层原理


下一篇:通过netstat和awk查看服务器的连接数