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; }
相关文章推荐
- 【bzoj4597】[Shoi2016]随机序列 线段树
- 【BZOJ4597】【Shoi2016】随机序列 线段树
- 【bzoj4597】【Shoi2016】【随机序列】【线段树】
- [BZOJ4597][SHOI2016]随机序列(线段树)
- [bzoj4597][Shoi2016]随机序列 线段树
- 【BZOJ4597】[Shoi2016]随机序列 线段树
- bzoj 4597: [Shoi2016]随机序列
- 【bzoj4597】 [Shoi2016]随机序列
- BZOJ 4597: [Shoi2016]随机序列
- bzoj4597 [Shoi2016]随机序列
- 4597: [Shoi2016]随机序列
- 【BZOJ4596】[Shoi2016]黑暗前的幻想乡 容斥+矩阵树定理
- [bzoj]4596: [Shoi2016]黑暗前的幻想乡
- [BZOJ]4418: [Shoi2013]扇形面积并 线段树
- bzoj 4596: [Shoi2016]黑暗前的幻想乡【容斥原理+矩阵树定理】
- 【BZOJ4540】【Hnoi2016】序列 线段树
- bzoj 4719: [Noip2016]天天爱跑步 线段树合并
- 【BZOJ】4596: [Shoi2016]黑暗前的幻想乡
- BZOJ 4653: [Noi2016]区间 线段树
- bzoj 4538: [Hnoi2016]网络 树链剖分+线段树