AtCoder Beginner Contest 357-F

Problem

同步于博客

Problem

You are given sequences of length N N N, A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\ldots,A_N) A=(A1,A2,,AN) and B = ( B 1 , B 2 , … , B N ) B=(B_1,B_2,\ldots,B_N) B=(B1,B2,,BN).

You are also given Q Q Q queries to process in order.

There are three types of queries:

  • 1 l r x : Add x x x to each of A l , A l + 1 , … , A r A_l, A_{l+1}, \ldots, A_r Al,Al+1,,Ar.
  • 2 l r x : Add x x x to each of B l , B l + 1 , … , B r B_l, B_{l+1}, \ldots, B_r Bl,Bl+1,,Br.
  • 3 l r : Print the remainder of ∑ i = l r ( A i × B i ) \displaystyle\sum_{i=l}^r (A_i\times B_i) i=lr(Ai×Bi) when divided by 998244353 998244353 998244353.

给你两个长度为 N N N 的序列 A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\ldots,A_N) A=(A1,A2,,AN) B = ( B 1 , B 2 , … , B N ) B=(B_1,B_2,\ldots,B_N) B=(B1,B2,,BN) 的序列。

需要按顺序处理 Q Q Q 个查询。

查询有三种类型:

  • 1 l r x : 在 A l , A l + 1 , … , A r A_l, A_{l+1}, \ldots, A_r Al,Al+1,,Ar 中的每一条添加 x x x
  • 2 l r x : 向 B l , B l + 1 , … , B r B_l, B_{l+1}, \ldots, B_r Bl,Bl+1,,Br 中的每一条添加 x x x
  • 3 l r : 打印 ∑ i = l r ( A i × B i ) \displaystyle\sum_{i=l}^r (A_i\times B_i) i=lr(Ai×Bi) 除以 998244353 998244353 998244353 的余数。

Constraints

  • 1 ≤ N , Q ≤ 2 × 1 0 5 1\leq N,Q\leq 2\times 10^5 1N,Q2×105
  • 0 ≤ A i , B i ≤ 1 0 9 0\leq A_i,B_i\leq 10^9 0Ai,Bi109
  • 1 ≤ l ≤ r ≤ N 1\leq l\leq r\leq N 1lrN
  • 1 ≤ x ≤ 1 0 9 1\leq x\leq 10^9 1x109
  • 全是整数

Solution

看到 N , Q N,Q N,Q 的取值范围,发现需要在 n log ⁡ n n\log n nlogn 的复杂度内解决。值域 1 ≤ x ≤ 1 0 9 1\le x\le 10^9 1x109 也不好做文章。

数列 A , B A,B A,B [ l , r ] [l,r] [l,r]上在进行操作1 l r x2 l r y后会变为
∑ i = l r ( A i + x ) × ( B i + y ) = ∑ i = l r A i × B i + x ∑ i = l r B i + y ∑ i = l r A i + x y ( r − l + 1 ) \begin{align} &\sum_{i=l}^r(A_i+x)\times (B_i+y)\\ &=\sum_{i=l}^rA_i\times B_i+x\sum_{i=l}^r B_i+y\sum_{i=l}^r A_i+xy(r-l+1) \end{align} i=lr(Ai+x)×(Bi+y)=i=lrAi×Bi+xi=lrBi+yi=lrAi+xy(rl+1)
故我们使用线段树维护三个量 ∑ A i × B i , ∑ A i , ∑ B i \sum A_i\times B_i,\sum A_i,\sum B_i Ai×Bi,Ai,Bi 和lazy标记 A d d a , A d d b Add_a,Add_b Adda,Addb

当执行1 l r x

  • ∑ A i × B i \sum A_i\times B_i Ai×Bi 增加 x ∑ B i + x ⋅ A d d b ⋅ ( r − l + 1 ) x\sum B_i+x\cdot Add_b\cdot(r-l+1) xBi+xAddb(rl+1)
  • ∑ A i \sum A_i Ai 增加 x ( r − l + 1 ) x(r-l+1) x(rl+1)
  • A d d a Add_a Adda 增加 x x x

当执行2 l r y

  • ∑ A i × B i \sum A_i\times B_i Ai×Bi 增加 y ∑ A i + y ⋅ A d d a ⋅ ( r − l + 1 ) y\sum A_i+y\cdot Add_a\cdot(r-l+1) yAi+yAdda(rl+1)
  • ∑ B i \sum B_i Bi 增加 y ( r − l + 1 ) y(r-l+1) y(rl+1)
  • A d d b Add_b Addb 增加 y y y

Code

#define P 998244353ll
#define N 800010
struct Edge{
	LL l,r,sumA,sumB,sum,addA,addB;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sumA(x) tree[x].sumA
#define sumB(x) tree[x].sumB
#define sum(x) tree[x].sum
#define addA(x) tree[x].addA
#define addB(x) tree[x].addB
}tree[N];
LL n,m; 
LL A[N],B[N];
void build(LL l,LL r,LL p)
{
	l(p)=l,r(p)=r;
	if(l==r){sumA(p)=A[l]%P;sumB(p)=B[l]%P;sum(p)=sumA(p)*sumB(p)%P;return;}
	LL mid=(l+r)>>1;
	build(l,mid,p<<1);
	build(mid+1,r,p<<1|1);
	sum(p)=sum(p<<1)+sum(p<<1|1);
	sumA(p)=sumA(p<<1)+sumA(p<<1|1);
	sumB(p)=sumB(p<<1)+sumB(p<<1|1);
	sum(p)%=P;
	sumA(p)%=P;
	sumB(p)%=P;
}
void spread(LL p)
{
	if(addA(p)||addB(p))
	{
		addA(p<<1)+=addA(p);
		addA(p<<1|1)+=addA(p);
		addB(p<<1)+=addB(p);
		addB(p<<1|1)+=addB(p);
		
		sum(p<<1)+=addA(p)*sumB(p<<1)+addB(p)*sumA(p<<1)+addA(p)*addB(p)%P*(r(p<<1)-l(p<<1)+1);
		sum(p<<1|1)+=addA(p)*sumB(p<<1|1)+addB(p)*sumA(p<<1|1)+addA(p)*addB(p)%P*(r(p<<1|1)-l(p<<1|1)+1);
		
		sumA(p<<1)+=addA(p)*(r(p<<1)-l(p<<1)+1);
		sumB(p<<1)+=addB(p)*(r(p<<1)-l(p<<1)+1);
		sumA(p<<1|1)+=addA(p)*(r(p<<1|1)-l(p<<1|1)+1);
		sumB(p<<1|1)+=addB(p)*(r(p<<1|1)-l(p<<1|1)+1);
		
		addA(p)=addB(p)=0;
		
		sum(p<<1)%=P;
		sum(p<<1|1)%=P;
		sumA(p<<1)%=P;
		sumA(p<<1|1)%=P;
		sumB(p<<1)%=P;
		sumB(p<<1|1)%=P;
		
		addA(p<<1)%=P;
		addB(p<<1)%=P;
		addA(p<<1|1)%=P;
		addB(p<<1|1)%=P;
	}
}
void change(LL l,LL r,LL p,LL k,bool isA)
{
	if(l<=l(p)&&r>=r(p)){
		if(isA) addA(p)+=k,sum(p)+=k*sumB(p),sumA(p)+=k*(r(p)-l(p)+1);
		else addB(p)+=k,sum(p)+=k*sumA(p),sumB(p)+=k*(r(p)-l(p)+1);
		sumA(p)%=P;sumB(p)%=P;sum(p)%=P;
		addA(p)%=P;addB(p)%=P;
		return;
	}
	LL mid=l(p)+r(p)>>1;
	spread(p);
	if(l<=mid) change(l,r,p<<1,k,isA);
	if(r>mid) change(l,r,p<<1|1,k,isA);
	sum(p)=sum(p<<1)+sum(p<<1|1);
	sumA(p)=sumA(p<<1)+sumA(p<<1|1);
	sumB(p)=sumB(p<<1)+sumB(p<<1|1);
	sum(p)%=P;
	sumA(p)%=P;
	sumB(p)%=P;
}

LL ask(LL l,LL r,LL p)
{
	if(l<=l(p)&&r>=r(p)) return sum(p);
	spread(p);
	LL mid=l(p)+r(p)>>1,val=0;
	if(l<=mid) val+=ask(l,r,p<<1);
	val%=P;
	if(r>mid) val+=ask(l,r,p<<1|1);
	val%=P;
	return val;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cout.precision(10);
	int q;
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>A[i];
	for(int i=1;i<=n;i++) cin>>B[i];
	build(1,n,1);
	while(q--)
	{
		int op,l,r,x;
		cin>>op>>l>>r;
		if(op!=3) cin>>x,change(l,r,1,x,(op==1));
		else cout<<ask(l,r,1)<<endl;
	}
	return 0;
}

Attention

开LL,多取模。

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值