P4340 [SHOI2016]随机序列(线段树)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4340 [SHOI2016]随机序列(线段树)相关的知识,希望对你有一定的参考价值。

P4340 [SHOI2016]随机序列(线段树)

结论:

只有前缀积有贡献。

因为第一个数前面是没有符号的,除了前缀积外,都可以通过加号变成减号、减号变加号使其贡献抵消。

接下来考虑每个前缀积的贡献。

我们可以枚举前缀积的位置 i i i

记录前缀积为 s i s_i si,第 i i i个符号可以有两种选择 + , − +,- +,

然后其他符号任意选。

所以一共有: 2 × 3 n − i − 1 2\\times 3^{n-i-1} 2×3ni1

然后总和就是:

a n s = ∑ i = 1 n − 1 s i × 2 × 3 n − i − 1 + s n \\large ans=\\sum\\limits_{i=1}^{n-1}s_i\\times 2\\times 3^{n-i-1}+s_n ans=i=1n1si×2×3ni1+sn

这里可以预处理每个 i i i对应的答案,然后修改 a i a_i ai就是相当于后缀区间乘法。

因为有模,所以要预处理逆元,但是 a i a_i ai非负, 0 0 0不存在逆元。所以此方法不可行。

考虑维护两个变量区间和 s s s 和区间 a i a_i ai的乘积 m m m

然后更新的话就是: a m = l s o n m + r s o n m , a s = l s o n s + r s o n s × l s o n m a_m=lson_m+rson_m,a_s=lson_s+rson_s\\times lson_m am=lsonm+rsonm,as=lsons+rsons×lsonm

// Problem: P4340 [SHOI2016]随机序列
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4340
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// Date: 2021-08-18 17:17:09
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int n,q;
//区间修改 区间求和
#define il inline 
#define lx x<<1
#define rx x<<1|1
#define len(x) (a[x].r-a[x].l+1)
struct node{
	int l,r,lz;
	ll s,m;
}a[N<<2];
int p[N],w[N];
il void re(int x){
	a[x].m=a[lx].m*a[rx].m%mod;
	a[x].s=(a[lx].s+a[rx].s*a[lx].m%mod)%mod;
}
il void bud(int x,int l,int r){
	a[x].l=l,a[x].r=r;
	if(l==r){
		a[x].m=w[l];
		a[x].s=l<n?w[l]*2LL*p[n-l-1]%mod:w[n];
		return;
	}
	int m=(l+r)>>1;bud(lx,l,m),bud(rx,m+1,r);
	re(x);
}
il void upd(int x,int pos,int v){
	if(a[x].l==a[x].r){
		a[x].m=w[pos]=v;
		a[x].s=a[x].l<n?v*2LL*p[n-pos-1]%mod:v;return;
	}
	int m=a[x].l+a[x].r>>1;
	if(pos<=m) upd(lx,pos,v);
	else upd(rx,pos,v);
	re(x);
}
int main(){
	scanf("%d%d",&n,&q);p[0]=1;
	for(int i=1;i<=n;i++){
		scanf("%d",&w[i]);
		p[i]=p[i-1]*3LL%mod;
	}
	bud(1,1,n);
	while(q--){
		int p,v;scanf("%d%d",&p,&v);
		upd(1,p,v);
		printf("%lld\\n",a[1].s);
	}
	return 0;
}

以上是关于P4340 [SHOI2016]随机序列(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

SHOI2016 随机序列

BZOJ4592[Shoi2015]脑洞治疗仪 线段树

bzoj4597: [Shoi2016]随机序列

SHOI2015脑洞治疗仪(恶心的线段树,区间最大子段和)

[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)

[SHOI2008]堵塞的交通traffic