[SHOI2016] 随机序列

4597: [Shoi2016]随机序列

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 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,表示要将 Ati 修改为 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

Sample Output

890543652
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;
}

  

 
posted @ 2018-03-26 21:57  蒟蒻JHY  阅读(441)  评论(0编辑  收藏  举报