【BZOJ】【1798】【AHOI2009】Seq维护序列

线段树

  属于线段树中级应用吧……

  要打两种标记:乘法和加法标记。一开始我想着可以像只有加法标记那样,永不下传,查询的时候依次累加就好了。后来发现不会写……只好每次update的时候……遇到标记!下传!query的时候遇到标记!下传!暴力地来搞……

  然后说下下传的细节:先传乘法,后传加法。因为传乘法标记的时候要连sum带add都要一起乘,如果先传add就会多乘……

  1 /**************************************************************
  2     Problem: 1798
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:3868 ms
  7     Memory:6748 kb
  8 ****************************************************************/
  9
 10 //BZOJ 1798
 11 #include<cstdio>
 12 #include<cstring>
 13 #include<cstdlib>
 14 #include<iostream>
 15 #include<algorithm>
 16 #define rep(i,n) for(int i=0;i<n;++i)
 17 #define F(i,j,n) for(int i=j;i<=n;++i)
 18 #define D(i,j,n) for(int i=j;i>=n;--i)
 19 //using namespace std;
 20 const int N=100086;
 21 typedef long long LL;
 22 //#define debug
 23 int n,m,P,a[N];
 24 int mul[N<<2],add[N<<2],sum[N<<2];
 25
 26 void read(int &v){
 27     v=0; int sign=1; char ch=getchar();
 28     while(ch<‘0‘ || ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();}
 29     while(ch>=‘0‘ && ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();}
 30     v*=sign;
 31 }
 32 #define mid (l+r>>1)
 33 #define L (o<<1)
 34 #define R (o<<1|1)
 35
 36 void Push_down(int o,int l,int r){
 37     if (mul[o]!=1){
 38         add[L]=((LL)add[L]*mul[o])%P; add[R]=((LL)add[R]*mul[o])%P;
 39         mul[L]=((LL)mul[L]*mul[o])%P; mul[R]=((LL)mul[R]*mul[o])%P;
 40         mul[o]=1;
 41     }
 42     if (add[o]!=0){
 43         add[L]=((LL)add[L]+add[o])%P; add[R]=((LL)add[R]+add[o])%P;
 44         add[o]=0;
 45     }
 46 }
 47 void Push_up(int o,int l,int r){
 48     if (l<r) sum[o]=(sum[L]+sum[R])%P; else sum[o]=0;
 49     sum[o]=((LL)sum[o]*mul[o]+(LL)add[o]*(r-l+1))%P;
 50 }
 51 void build(int o,int l,int r){
 52     if (l==r) add[o]=sum[o]=a[l],mul[o]=1;
 53     else{
 54         build(L,l,mid);
 55         build(R,mid+1,r);
 56         add[o]=0; mul[o]=1;
 57         Push_up(o,l,r);
 58     }
 59 }
 60 int ql,qr;
 61 void update_add(int o,int l,int r,int v){
 62     if (ql<=l && qr>=r)
 63         add[o]=((LL)add[o]+v)%P;
 64     else{
 65         if (mul[o]!=1 || add[o]) Push_down(o,l,r);
 66         if (ql<=mid) update_add(L,l,mid,v); else Push_up(L,l,mid);
 67         if (qr>mid) update_add(R,mid+1,r,v); else Push_up(R,mid+1,r);
 68     }
 69     Push_up(o,l,r);
 70 }
 71 void update_mul(int o,int l,int r,int v){
 72     if (ql<=l && qr>=r)
 73         mul[o]=((LL)mul[o]*v)%P,add[o]=(LL)add[o]*v%P;
 74     else{
 75         if (mul[o]!=1 || add[o]) Push_down(o,l,r);
 76         if (ql<=mid) update_mul(L,l,mid,v); else Push_up(L,l,mid);
 77         if (qr>mid) update_mul(R,mid+1,r,v); else Push_up(R,mid+1,r);
 78     }
 79     Push_up(o,l,r);
 80 }
 81 int sumv;
 82 void query(int o,int l,int r){
 83     if (ql<=l && qr>=r)
 84         sumv=((LL)sumv+sum[o])%P;
 85     else{
 86         if (mul[o]!=1 || add[o]) {Push_down(o,l,r); Push_up(L,l,mid); Push_up(R,mid+1,r);}
 87         if (ql<=mid) query(L,l,mid);
 88         if (qr>mid) query(R,mid+1,r);
 89     }
 90 }
 91 int ans[N],cnt=0;
 92 int main(){
 93     #ifndef ONLINE_JUDGE
 94     freopen("input.txt","r",stdin);
 95 //  freopen("output.txt","w",stdout);
 96     #endif
 97     read(n); read(P);
 98     F(i,1,n) read(a[i]);
 99 //  F(i,1,n) printf("%d ",a[i]);
100 //  printf("\n");
101     build(1,1,n);
102
103     read(m);
104 //  printf("m=%d\n",m);
105     int c,v;
106     F(i,1,m){
107         read(c); read(ql); read(qr);
108 //      printf("c=%d\n",c);
109         switch(c){
110             case 1: read(v); update_mul(1,1,n,v); break;
111             case 2: read(v); update_add(1,1,n,v); break;
112             case 3: sumv=0; query(1,1,n); ans[cnt++]=sumv;break;
113         }
114     }
115     rep(i,cnt-1) printf("%d\n",ans[i]);
116     printf("%d",ans[cnt-1]);
117     return 0;
118 }

时间: 2024-10-25 01:06:36

【BZOJ】【1798】【AHOI2009】Seq维护序列的相关文章

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列

bzoj 1798 [Ahoi2009]Seq 维护序列seq(线段树+传标)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1798 [题意] 给定一个序列,要求提供区间乘/加,以及区间求和的操作 [思路] 线段树+传标. 下传标记的方式可以类比这里 click here [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio>

BZOJ 1798 AHOI2009 Seq 维护序列 线段树

题目大意:维护一个序列,提供三种操作: 1.将区间中每个点的权值乘上一个数 2.将区间中每个点的权值加上一个数 3.求一段区间的和对p取模的值 2631的超^n级弱化版.写2631之前能够拿这个练练手... 线段树区间改动,让学校的大神指导了一下ZKW的区间改动方法,非常好理解,可是代码还是快不了. . . 回头再改改代码吧 可能是我写的太渣了 #include<cstdio> #include<cstring> #include<iostream> #include&

bzoj 1798 [Ahoi2009]Seq 维护序列seq

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 线段树区间更新: 1. 区间同同时加上一个数 2. 区间同时乘以一个数 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 #define lc root<<1 6 #define rc root<<1|1

BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)

 题目:点击打开链接 大意:一个数组,三个操作,第一种是区间[a,b]每个数乘乘,第二种是区间[a,b]每个数加c,第三种是查询[a,b]区间的和并对p取摸. 两种操作就不能简单的只往下传标记.每次传乘法标记时,要把加法标记同时乘上乘法标记,例如某个区间先进来一个加法标记add,之后又进来一个乘法标记mul. 那么结果为(x + add) * mul = x * mul + add * mul.这样向下传标记的时候就相对独立.递归边界更新加法标记之前先乘上该节点的mul,左右儿子down的时

bzoj 1798 [Ahoi2009]Seq 维护序列seq ——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1798 先乘后加,就可给加法标记乘上乘法标记. 注意可能有 *0 的操作,所以 pshd 时不是 cg[ cr ]>1 而是 cg[ cr ]!=1 . #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #de

BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树

题意:链接 方法:线段树 解析: 俩标记sb题 更新乘的时候更新加 完了 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define N 100010 using namespace std; typedef

1798: [Ahoi2009]Seq 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5886  Solved: 2087[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和

【BZOJ】1798: [Ahoi2009]Seq 维护序列seq(线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=1798 之前写了个快速乘..........................20多s...... 还好1a.. 那么本题就是维护两个tag即可.和上一题一样. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #inc

bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 497  Solved: 203 [Submit][Status][Discuss] Description 老 师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的