(1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>
来源:互联网 发布:怎么遍历json数组 编辑:程序博客网 时间:2024/05/20 22:35
题目
Time Limit: 30 Sec
Memory Limit: 64 MB
Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input
第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
Sample Output
2
35
8
HINT
【样例说明】
初始时数列为(1,2,3,4,5,6,7)。
经过第1次操作后,数列为(1,10,15,20,25,6,7)。
对第2次操作,和为10+15+20=45,模43的结果是2。
经过第3次操作后,数列为(1,10,24,29,34,15,16}
对第4次操作,和为1+10+24=35,模43的结果是35。
对第5次操作,和为29+34+15+16=94,模43的结果是8。
测试数据规模如下表所示
数据编号 1 2 3 4 5 6 7 8 9 10
N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
题解
- 裸线段树+特殊乘法操作
- 乘法和加法各一个标记
- 更新的时候,如果是加操作,直接套用裸线段树的模式
如果是乘操作,则既要把乘的标记乘v,加的标记也要乘v,简单说就是先乘后加,原理是乘法分配律
(a+b)*v=a*v+b*v,其中a是原数,b是加的标记,v是此时乘的数 - pushdown时并起来就好了
- 另外记得随时取模
代码
#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>using namespace std;const int M=100010;int n,p,m;struct node{ int L,R; long long sum,c1,c2;//c1 >- * c2 >- +}t[M*4+5];long long x;void pushup(int pos){ t[pos].sum=(t[pos<<1].sum+t[pos<<1|1].sum)%p;}void build(int pos,int L,int R){ t[pos].L=L; t[pos].R=R; t[pos].sum=t[pos].c2=0; t[pos].c1=1;//初始化为1 if(L==R){ scanf("%lld",&x); t[pos].sum=(x%p); } else{ int mid=(L+R)>>1; build(pos<<1,L,mid); build(pos<<1|1,mid+1,R); pushup(pos); }}void pushdown(int pos){ if(t[pos].c1==1&&t[pos].c2==0) return; int L1=t[pos<<1].R-t[pos<<1].L+1; int L2=t[pos<<1|1].R-t[pos<<1|1].L+1; t[pos<<1].c1=(t[pos].c1*t[pos<<1].c1)%p; t[pos<<1|1].c1=(t[pos].c1*t[pos<<1|1].c1)%p; t[pos<<1].c2=(t[pos].c1*t[pos<<1].c2+t[pos].c2)%p; t[pos<<1|1].c2=(t[pos].c1*t[pos<<1|1].c2+t[pos].c2)%p; t[pos<<1].sum=(t[pos<<1].sum*t[pos].c1+L1*t[pos].c2)%p; t[pos<<1|1].sum=(t[pos<<1|1].sum*t[pos].c1+L2*t[pos].c2)%p; t[pos].c1=1; t[pos].c2=0;}void update1(int pos,int ll,int rr,int v){ int L=t[pos].L; int R=t[pos].R; if(ll>R||rr<L) return; if(ll<=L&&rr>=R){ t[pos].c1=(t[pos].c1*v)%p; t[pos].c2=(t[pos].c2*v)%p; t[pos].sum=(t[pos].sum*v)%p; return; } pushdown(pos); update1(pos<<1,ll,rr,v); update1(pos<<1|1,ll,rr,v); pushup(pos);}void update2(int pos,int ll,int rr,int v){ int L=t[pos].L; int R=t[pos].R; if(ll>R||rr<L) return; if(ll<=L&&rr>=R){ t[pos].c2=(t[pos].c2+v)%p; t[pos].sum=(t[pos].sum+(R-L+1)*v)%p; return; } pushdown(pos); update2(pos<<1,ll,rr,v); update2(pos<<1|1,ll,rr,v); pushup(pos);}long long query(int pos,int ll,int rr){ int L=t[pos].L; int R=t[pos].R; if(ll>R||rr<L) return 0; if(ll<=L&&rr>=R) return t[pos].sum%p; pushdown(pos); return (query(pos<<1,ll,rr)+query(pos<<1|1,ll,rr))%p;}int main(){ scanf("%d%d",&n,&p); build(1,1,n); scanf("%d",&m); int op,a,b,z; for(int i=1;i<=m;++i){ scanf("%d",&op); if(op==1){ scanf("%d%d%d",&a,&b,&z); update1(1,a,b,z); } if(op==2){ scanf("%d%d%d",&a,&b,&z); update2(1,a,b,z); } if(op==3){ scanf("%d%d",&a,&b); printf("%lld\n",query(1,a,b)%p); } } return 0;}
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)
- (1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq (线段树)
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树
- 1798: [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq|线段树
- 【BZOJ】1798 [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq 线段树题解
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树模板
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树
- bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和
- HYSBZ 1798(Ahoi2009) Seq 维护序列seq(区间更新+加法乘法混合操作)
- Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)
- BZOJ 题目1798: [Ahoi2009]Seq 维护序列seq(双标记线段树)
- BZOJ1798:[Ahoi2009]Seq 维护序列 线段树
- Android studio gradle中分渠道加载res、libraries及Class
- bug修复-android中的onCreate两个参数的方法是什么鬼?
- 61、二叉搜索树的第k个结点
- 数据转发中心高并发访问次数统计(mysql实现)
- javascript Array数组常用的方法
- (1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>
- docker--容器和镜像
- Java,bit比特,byte字节,char字符,short,int,long,float,double,string,字母,汉字/编码等
- 面试题7:用两个栈实现队列
- 关于地理数据坐标转换
- TimerTask定时执行删除文件
- 将myeclipse的控制台固定住
- pagehelper插件使用时查询不到数据
- Qt 加载动态库DLL