bzoj 1798 维护序列seq

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798

题解:

  高级一点的线段树,加上了区间乘法运算,则需要增加一个数组mulv记录乘的因数,在下放更新sumv和addv值的都时候要先乘再加

  被蓝书的写法坑了,就一直搞不懂下放和sumv、addv数组的具体用法,导致网上大犇们的程序我基本都看不懂,写完这道题感觉重新学了一遍线段树

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 400010
 4 #define LL long long
 5 LL MOD,sumv[MAXN],addv[MAXN],mulv[MAXN];
 6 int n,m,t1,y1,y2,v;
 7 void maintain(int o,int len)//下放
 8 {
 9     int lc=o<<1,rc=(o<<1)+1,M=len>>1;
10     if(mulv[o]!=1||addv[o])
11     {
12         mulv[lc]=(mulv[lc]*mulv[o])%MOD;
13         mulv[rc]=(mulv[rc]*mulv[o])%MOD;
14         addv[lc]=((addv[lc]*mulv[o])+addv[o])%MOD;
15         addv[rc]=((addv[rc]*mulv[o])+addv[o])%MOD;
16         sumv[lc]=(sumv[lc]*mulv[o]+(len-M)*addv[o])%MOD;
17         sumv[rc]=(sumv[rc]*mulv[o]+M*addv[o])%MOD;
18     }
19     addv[o]=0;
20     mulv[o]=1;
21 }
22 void build(int o,int L,int R)
23 {
24     int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2;
25     if(L==R)
26     {
27         scanf("%lld",&sumv[o]);
28         return;
29     }
30     build(lc,L,M);
31     build(rc,M+1,R);
32     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
33 }
34 void update(int o,int L,int R)
35 {
36     int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2;
37     if(y1<=L&&y2>=R)
38     {
39         if(t1==1)
40         {
41             addv[o]=(addv[o]*v)%MOD;
42             sumv[o]=(sumv[o]*v)%MOD;
43             mulv[o]=(mulv[o]*v)%MOD;
44         }
45         else
46         {
47             addv[o]=(addv[o]+v)%MOD;
48             sumv[o]=(sumv[o]+v*(R-L+1))%MOD;
49         }
50         return;
51     }
52     maintain(o,R-L+1);
53     if(y1<=M)update(lc,L,M);
54     if(y2>M)update(rc,M+1,R);
55     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
56 }
57 LL query(int o,int L,int R)
58 {
59     int lc=o<<1,rc=(o<<1)+1,M=(L+R)>>1;
60     if(y1<=L&&y2>=R)return sumv[o]%MOD;
61     maintain(o,R-L+1);
62     LL ans=0;
63     if(y1<=M)ans=(query(lc,L,M))%MOD;
64     if(y2>M)ans+=(query(rc,M+1,R))%MOD;
65     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
66     return ans%MOD;
67 }
68 int main()
69 {
70     scanf("%d%lld",&n,&MOD);
71     for(int i=1;i<=400009;i++)mulv[i]=1;
72     build(1,1,n);
73     scanf("%d",&m);
74     while(m--)
75     {
76         scanf("%d%d%d",&t1,&y1,&y2);
77         if(t1!=3)
78         {
79             scanf("%d",&v);
80             update(1,1,n);
81         }
82         else printf("%lld\n",query(1,1,n));
83     }
84     return 0;
85 }
时间: 2024-08-04 01:01:10

bzoj 1798 维护序列seq的相关文章

BZOJ 1798 维护序列

我偏要先下传加... #include<iostream> #include<cstdio> #include<cstring> #define maxn 100500 using namespace std; long long ls[maxn<<2],rs[maxn<<2],val[maxn<<2],lazy1[maxn<<2],lazy2[maxn<<2]; long long n,p,m,a,b,c,d

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)询问数列

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)询问数列中的一段数的和

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)询问数列中的一段数的

bzoj1798[Ahoi2009]Seq 维护序列seq

bzoj1798[Ahoi2009]Seq 维护序列seq 题意: 维护序列,支持区间加.区间乘.区间求和模一个数.序列大小和操作数≤100000 题解: 线段树,加标记和乘标记的处理同bzoj4003.模的时候注意细节. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define m

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树多重标记下传)

www.cnblogs.com/shaokele/ bzoj1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值

【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

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 Ahoi 2009 维护序列seq

题目大意:维护一个序列,能够区间加,区间乘,然后取区间和模一个数的值. 思路:线段树维护一个有两个域的标记,一个表示加,一个表示乘.下传的时候一起下传,先乘后加. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define MO p #define LEFT (pos << 1) #de