【bzoj1798】[Ahoi2009]Seq 维护序列seq

大意:一个数组,三个操作,第一种是区间[a,b]每个数乘乘,第二种是区间[a,b]每个数加c,第三种是查询[a,b]区间的和并对p取摸。

两种操作就不能简单的只往下传标记。每次传乘法标记时,要把加法标记同时乘上乘法标记,例如某个区间先进来一个加法标记add,之后又进来一个乘法标记mul。

那么结果为(x+add)*mul=x*mul+add*mul。这样向下传标记的时候就相对独立。递归边界更新加法标记之前先乘上该节点的mul,左右儿子down的时候先将儿子的add乘上本节点的mul。

最后说一下sum,比如本节点的存在加法标记x和乘法标记y,并且是先加上x,再乘上y,则左儿子的sum要更新为(sum+x)*y。由于乘法标记传到本节点的时候更新了加法标记,x =x*y,所以sum[o<<1]=(左区间的长度*x)+sum[o<<1]*y。

 

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 using namespace std;
  8  
  9 typedef long long LL;
 10  
 11 #define N 100010
 12  
 13 int n,m;
 14 int askd,al,ar,ask;
 15 LL p;
 16   
 17 LL add[N<<2],sum[N<<2],mul[N<<2];
 18  
 19 void pushup(int now)
 20 {
 21     sum[now]=(sum[now<<1]+sum[now<<1|1])%p;
 22 }
 23  
 24 void pushdown(int now,int d)
 25 {
 26     if (add[now]!=0 || mul[now]!=1)
 27     {
 28         mul[now<<1]=mul[now<<1]*mul[now]%p;
 29         mul[now<<1|1]=mul[now<<1|1]*mul[now]%p;
 30         add[now<<1]=(add[now]+add[now<<1]*mul[now])%p;
 31         add[now<<1|1]=(add[now]+add[now<<1|1]*mul[now])%p;
 32         sum[now<<1]=(add[now]*(d-(d>>1))+sum[now<<1]*mul[now])%p;
 33         sum[now<<1|1]=(add[now]*(d>>1)+sum[now<<1|1]*mul[now])%p;
 34         add[now]=0;
 35         mul[now]=1;
 36     }
 37 }
 38  
 39 void build(int nowl,int nowr,int now)
 40 {
 41     sum[now]=0;
 42     mul[now]=1;
 43     if (nowl==nowr)
 44     {
 45         scanf("%lld",&sum[now]);
 46         return ;
 47     }
 48     int mid=(nowl+nowr)>>1;
 49     build(nowl,mid,now<<1);
 50     build(mid+1,nowr,now<<1|1);
 51     pushup(now);
 52 }
 53  
 54 void updata_mul(int nowl,int nowr,int now,int l,int r,int c)
 55 {
 56     if (nowl>=l && nowr<=r)
 57     {
 58         add[now]=add[now]*c%p;
 59         sum[now]=sum[now]*c%p;
 60         mul[now]=mul[now]*c%p;
 61         return ;
 62     }
 63     pushdown(now,nowr-nowl+1);
 64     int mid=(nowl+nowr)>>1;
 65     if (l<=mid)
 66         updata_mul(nowl,mid,now<<1,l,r,c);
 67     if (r>mid)
 68         updata_mul(mid+1,nowr,now<<1|1,l,r,c);
 69     pushup(now);
 70 }
 71  
 72 void updata_add(int nowl,int nowr,int now,int l,int r,int c)
 73 {
 74     if (nowl>=l && nowr<=r)
 75     {
 76         add[now]=(add[now]+c)%p;
 77         sum[now]=(sum[now]+c*(nowr-nowl+1))%p;
 78         return ;
 79     }
 80     pushdown(now,nowr-nowl+1);
 81     int mid=(nowl+nowr)>>1;
 82     if (l<=mid)
 83         updata_add(nowl,mid,now<<1,l,r,c);
 84     if (r>mid)
 85         updata_add(mid+1,nowr,now<<1|1,l,r,c);
 86     pushup(now);
 87 }
 88  
 89 LL query(int nowl,int nowr,int now,int l,int r)
 90 {
 91     LL res(0);
 92     if (nowl>=l && nowr<=r)
 93         return sum[now];
 94     pushdown(now,nowr-nowl+1);
 95     int mid=(nowl+nowr)>>1;
 96     if (l<=mid)
 97         res=(res+query(nowl,mid,now<<1,l,r))%p;
 98     if (r>mid)
 99         res=(res+query(mid+1,nowr,now<<1|1,l,r))%p;
100     return res;
101 }
102  
103 int main()
104 {
105     scanf("%d%lld",&n,&p);
106     build(1,n,1);
107     scanf("%d",&m);
108     while (m--)
109     {
110         scanf("%d",&askd);
111         if (askd==1)
112         {
113             scanf("%d%d%d",&al,&ar,&ask);
114             updata_mul(1,n,1,al,ar,ask);
115         }
116         if (askd==2)
117         {
118             scanf("%d%d%d",&al,&ar,&ask);
119             updata_add(1,n,1,al,ar,ask);
120         }
121         if (askd==3)
122         {
123             scanf("%d%d",&al,&ar);
124             printf("%lld\n",query(1,n,1,al,ar));
125         }
126     }
127     return 0;
128 }

 

posted @ 2016-05-15 15:46  Yangjiyuan  阅读(144)  评论(0编辑  收藏  举报