您的位置:首页 > 其它

bzoj 4597: [Shoi2016]随机序列 线段树

2018-01-19 10:48 357 查看

题意

你的面前有N个数排成一行。分别为A1, A2, … , An。你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者减号或者乘号。那么一共有 3^(n-1) 种可能的表达式。你对所有可能的表达式的值的和非常感兴趣。但这毕竟太简单了,所以你还打算支持一个修改操作,可以修改某个Ai 的值。你能够编写一个程序对每个修改都输出修改完之后所有可能表达式的和吗?注意,修改是永久的,也就是说每次修改都是在上一次修改的基础上进行, 而不是在最初的表达式上进行。

N,Q<=100000。

分析

无聊题。

我们把每一段连续的乘号分别讨论算贡献。不难发现如果这段的开头不是A1,那么前面放正号或负号,恰好可以把这一段的贡献抵消掉。

那么我们要求的就是前缀积的和。

用线段树维护就好了。

如果没有0的话,可以直接乘逆元。但有0的话,可以开一个set维护每个0的位置,然后把位置0设为1即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;

typedef long long LL;

const int N=100005;
const int MOD=1000000007;

int n,m,a
,s
,ny
;
struct tree{int s,tag;}t[N*4];
set<int> se;

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

void build(int d,int l,int r)
{
t[d].tag=1;
if (l==r) {t[d].s=s[l];return;}
int mid=(l+r)/2;
build(d*2,l,mid);build(d*2+1,mid+1,r);
t[d].s=(t[d*2].s+t[d*2+1].s)%MOD;
}

void pushdown(int d)
{
if (t[d].tag==1) return;
int w=t[d].tag;t[d].tag=1;
t[d*2].s=(LL)t[d*2].s*w%MOD;t[d*2].tag=(LL)t[d*2].tag*w%MOD;
t[d*2+1].s=(LL)t[d*2+1].s*w%MOD;t[d*2+1].tag=(LL)t[d*2+1].tag*w%MOD;
}

void ins(int d,int l,int r,int x,int y,int z)
{
if (l<r) pushdown(d);
if (l==x&&r==y) {t[d].s=(LL)t[d].s*z%MOD;t[d].tag=(LL)t[d].tag*z%MOD;return;}
int mid=(l+r)/2;
if (y<=mid) ins(d*2,l,mid,x,y,z);
else if (x>mid) ins(d*2+1,mid+1,r,x,y,z);
else ins(d*2,l,mid,x,mid,z),ins(d*2+1,mid+1,r,mid+1,y,z);
t[d].s=(t[d*2].s+t[d*2+1].s)%MOD;
}

int query(int d,int l,int r,int x,int y)
{
if (l<r) pushdown(d);
if (l==x&&r==y) return t[d].s;
int mid=(l+r)/2;
if (y<=mid) return query(d*2,l,mid,x,y);
else if (x>mid) return query(d*2+1,mid+1,r,x,y);
else return (query(d*2,l,mid,x,mid)+query(d*2+1,mid+1,r,mid+1,y))%MOD;
}

int main()
{
ny[0]=ny[1]=1;
for (int i=2;i<=10000;i++) ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
n=read();m=read();s[0]=2;
for (int i=0;i<n-1;i++) s[0]=(LL)s[0]*3%MOD;
for (int i=1;i<=n;i++)
{
a[i]=read();
s[i]=(LL)s[i-1]*(a[i]?a[i]:1)%MOD*ny[3]%MOD;
if (!a[i]) se.insert(i);
}
s
=(LL)s
*3%MOD*ny[2]%MOD;
build(1,1,n);
while (m--)
{
int x=read(),y=read();
if (!a[x]) se.erase(x);
else ins(1,1,n,x,n,ny[a[x]]);
a[x]=y;
if (!a[x]) se.insert(x);
else ins(1,1,n,x,n,a[x]);
int p;
if (!se.size()) p=n;
else p=*se.begin()-1;
printf("%d\n",query(1,1,n,1,p));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: