4597: [Shoi2016]随机序列
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 327 Solved: 192
[Submit][Status][Discuss]
Description
你的面前有N个数排成一行。分别为A1, A2, … , An。你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者
减号或者乘号。那么一共有 3^(n-1) 种可能的表达式。你对所有可能的表达式的值的和非常感兴趣。但这毕竟太
简单了,所以你还打算支持一个修改操作,可以修改某个Ai 的值。你能够编写一个程序对每个修改都输出修改完
之后所有可能表达式的和吗?注意,修改是永久的,也就是说每次修改都是在上一次修改的基础上进行, 而不是
在最初的表达式上进行。
Input
第一行包含 2 个正整数 N 和 Q,为数的个数和询问的个数。
接下来一行 n 个非负整数,依次表示a1,a2...an
在接下来 Q 行,其中第 i 行两个非负整数Ti 和Vi,表示要将 A
ti 修改为 Vi。其中 1 ≤ Ti ≤ N。
保证对于 1 ≤ J ≤ N, 1 ≤ i≤ Q,都有 Aj,Vi ≤ 10^4。
N,Q<=100000,本题仅有三组数据
Output
输出共 Q 行,其中第 i 行表示第 i 个询问之后所有可能表达式的和,对10^9 + 7 取模。
Sample Input
5 5
9384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60
9384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60
Sample Output
890543652
252923708
942282590
228728040
608998099
252923708
942282590
228728040
608998099
HINT
Source
一个非常神奇的事情是,只有第一个由*连成的联通块对答案有贡献,后面的联通块都没有贡献。
虽然说是神奇,但还是比较显而易见的233。就比如我们再填上+和-之前,*已经连出了若干联通块,我们只需要在剩下的空当中填上+或-即可完成一次操作。然而每一种操作都对应着有且只有一个反操作,使得除了*都相同以外,一种操作填+的位置在另一种中都是-,而填-的位置都是+,那么两种操作的和就是第一个由*连成的联通块的元素积*2,剩下的联通块的积都被抵消掉了。
所以答案就是 a[1] * 2 * 3^(n-2) + ..... a[1] * a[2] * a[3] * ... * a[n-1] * 2 + a[1] * a[2] *...* a[n]。
于是我们就可以在线段树 的每个位置维护 a[1] * ...* a[i] * 2 * 3^(n-i-1) [或者a[1] *..... *a[n]] ;
修改的话,就是一个后缀区间乘上一个数,直接做就行了。
但是为什么在洛谷上我的标记永久化线段树 被 下传标记的线段树 艹爆了 2333,而在bzoj 却是相反的情况。。。
这是标记下传的:
/**************************************************************
Problem: 4597
User: JYYHH
Language: C++
Result: Accepted
Time:584 ms
Memory:6372 kb
****************************************************************/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int ha=1000000007;
const int maxn=100005;
int a[maxn],f[maxn],hz,pos,qz[maxn];
int c[maxn],n,Q,val,ans,b[maxn],w;
int tag[maxn*4],sum[maxn*4],le,ri;
inline int add(int x,int y){
x+=y;
return x>=ha?x-ha:x;
}
inline int ksm(int x,int y){
int an=1;
for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
return an;
}
inline void maintain(int o,int lc,int rc){
sum[o]=add(sum[lc],sum[rc]);
}
inline void change(int o,int MUL){
tag[o]=tag[o]*(ll)MUL%ha;
sum[o]=sum[o]*(ll)MUL%ha;
}
inline void pushdown(int o,int lc,int rc){
if(tag[o]>1){
change(lc,tag[o]),change(rc,tag[o]);
tag[o]=1;
}
}
void build(int o,int l,int r){
tag[o]=1;
if(l==r){
sum[o]=(l==n?qz[l]:qz[l]*2ll*(ll)c[n-l-1]%ha);
return;
}
int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
build(lc,l,mid),build(rc,mid+1,r);
maintain(o,lc,rc);
}
void update(int o,int l,int r){
if(l>=le&&r<=ri){
change(o,w);
return;
}
int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
pushdown(o,lc,rc);
if(le<=mid) update(lc,l,mid);
if(ri>mid) update(rc,mid+1,r);
maintain(o,lc,rc);
}
inline void solve(){
build(1,1,n);
while(Q--){
scanf("%d%d",&pos,&val);
le=pos,ri=n,w=val*(ll)ksm(a[pos],ha-2)%ha;
a[pos]=val;
update(1,1,n);
printf("%d\n",sum[1]);
}
}
int main(){
scanf("%d%d",&n,&Q),c[0]=qz[0]=1;
for(int i=1;i<=n;i++) c[i]=add(c[i-1],add(c[i-1],c[i-1]));
for(int i=1;i<=n;i++){
scanf("%d",a+i);
qz[i]=qz[i-1]*(ll)a[i]%ha;
}
solve();
return 0;
}
然后标记永久化的
/**************************************************************
Problem: 4597
User: JYYHH
Language: C++
Result: Accepted
Time:460 ms
Memory:6372 kb
****************************************************************/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int ha=1000000007;
const int maxn=100005;
int a[maxn],f[maxn],hz,pos,qz[maxn];
int c[maxn],n,Q,val,ans,b[maxn],w;
int tag[maxn*4],sum[maxn*4],le,ri;
inline int add(int x,int y){
x+=y;
return x>=ha?x-ha:x;
}
inline int ksm(int x,int y){
int an=1;
for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
return an;
}
inline void maintain(int o,int lc,int rc){
sum[o]=tag[o]*(ll)add(sum[lc],sum[rc])%ha;
}
inline void change(int o,int MUL){
tag[o]=tag[o]*(ll)MUL%ha;
sum[o]=sum[o]*(ll)MUL%ha;
}
void build(int o,int l,int r){
tag[o]=1;
if(l==r){
sum[o]=(l==n?qz[l]:qz[l]*2ll*(ll)c[n-l-1]%ha);
return;
}
int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
build(lc,l,mid),build(rc,mid+1,r);
maintain(o,lc,rc);
}
void update(int o,int l,int r){
if(l>=le&&r<=ri){
change(o,w);
return;
}
int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
if(le<=mid) update(lc,l,mid);
if(ri>mid) update(rc,mid+1,r);
maintain(o,lc,rc);
}
inline void solve(){
build(1,1,n);
while(Q--){
scanf("%d%d",&pos,&val);
le=pos,ri=n,w=val*(ll)ksm(a[pos],ha-2)%ha;
a[pos]=val;
update(1,1,n);
printf("%d\n",sum[1]);
}
}
int main(){
scanf("%d%d",&n,&Q),c[0]=qz[0]=1;
for(int i=1;i<=n;i++) c[i]=add(c[i-1],add(c[i-1],c[i-1]));
for(int i=1;i<=n;i++){
scanf("%d",a+i);
qz[i]=qz[i-1]*(ll)a[i]%ha;
}
solve();
return 0;
}