5039: [Jsoi2014]序列维护

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 323  Solved: 193
[Submit][Status][Discuss]

Description

JYY 有一个维护数列的任务。 他希望你能够来帮助他完成。
JYY 现在有一个长度为 N 的序列 a1,a2,…,aN,有如下三种操作:
1、 把数列中的一段数全部乘以一个值;
2、 把数列中的一段数全部加上一个值;
3、 询问序列中的一段数的和。
由于答案可能很大,对于每个询问,你只需要告诉 JYY 这个询问的答案对 P
取模的结果即可。

Input

第一行包含两个正整数, N 和 P;
第二行包含 N 个非负整数,从左到右依次为 a1,a2,…,aN。
第三行有一个整数 M,表示操作总数。
接下来 M 行,每行满足如下三种形式之一:
1、“ 1 t g c”(不含引号)。表示把所有满足 t ≤ i ≤ g 的 ai 全部乘以 c;
2、“ 2 t g c”(不含引号)。表示把所有满足 t ≤ i ≤ g 的 ai 全部加上 c;
3、“ 3 t g”(不含引号)。表示询问满足 t ≤ i ≤ g 的 ai 的和对 P 取模的值。
1 ≤ N,M ≤ 10^5, 1 ≤ P, c, ai ≤ 2*10^9, 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
【样例说明】
初始时数列为(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。
  由于区分不出是先加还是先减,维护add[i],和mul[i]表示对于i节点对应的区间内的所有数x->x*mul[i]+add[i]。标记下放时推一下公式就好了。
  

 #include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<time.h>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define debug puts("debug")
#define LL long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f const int MAX=;
int N;
LL P;
struct Seg{
#define lc (id<<1)
#define rc (id<<1|1)
#define mid ((L+R)>>1)
LL sum[MAX<<];
LL mul[MAX<<],add[MAX<<];
void pushup(int id){
sum[id]=(sum[lc]+sum[rc])%P;
}
void pushdown(int id,int L,int R){
if(mul[id]==&&add[id]==) return;
add[lc]=(add[id]+mul[id]*add[lc])%P;
mul[lc]=mul[id]*mul[lc]%P;
sum[lc]=(sum[lc]*mul[id]%P+((LL)mid-L+)*add[id]%P)%P; add[rc]=(add[id]+mul[id]*add[rc])%P;
mul[rc]=(mul[rc]*mul[id])%P;
sum[rc]=(sum[rc]*mul[id]%P+((LL)R-mid)*add[id]%P)%P; add[id]=;
mul[id]=;
}
void build(int id,int L,int R){
mul[id]=;
add[id]=;
if(L==R){
scanf("%lld",&sum[id]);
sum[id]%=P;
return ;
}
build(lc,L,mid);
build(rc,mid+,R);
pushup(id);
}
void update1(int id,int L,int R,int l,int r,int v){
if(L>=l&&R<=r){
sum[id]=sum[id]*v%P;
mul[id]=mul[id]*v%P;
add[id]=add[id]*v%P;
return ;
}
pushdown(id,L,R);
if(l<=mid) update1(lc,L,mid,l,r,v);
if(r>mid) update1(rc,mid+,R,l,r,v);
pushup(id);
}
void update2(int id,int L,int R,int l,int r,int v){
if(L>=l&&R<=r){
add[id]+=v;
add[id]%=P;
sum[id]+=((LL)R-L+)*v;
sum[id]%=P;
return;
}
pushdown(id,L,R);
if(l<=mid) update2(lc,L,mid,l,r,v);
if(r>mid) update2(rc,mid+,R,l,r,v);
pushup(id);
}
LL query(int id,int L,int R,int l,int r){
if(L>=l&&R<=r){
return sum[id];
}
pushdown(id,L,R);
if(r<=mid) return query(lc,L,mid,l,r);
else if(l>mid) return query(rc,mid+,R,l,r);
else return (query(lc,L,mid,l,r)+query(rc,mid+,R,l,r))%P;
}
}ac;
int main(){
int i,j,op,t,g,m,c;
scanf("%d%lld",&N,&P);
ac.build(,,N);
scanf("%d",&m);
while(m--){
scanf("%d",&op);
if(op==){
scanf("%d%d%d",&t,&g,&c);
ac.update1(,,N,t,g,c);
}
else if(op==){
scanf("%d%d%d",&t,&g,&c);
ac.update2(,,N,t,g,c);
}
else{
scanf("%d%d",&t,&g);
printf("%lld\n",ac.query(,,N,t,g));
}
}
return ;
}

bzoj-5049-线段树的更多相关文章

  1. BZOJ 1798 (线段树||分块)的标记合并

    我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...

  2. bzoj 3999 线段树区间提取 有序链剖

    看错题目了,想成每个城市都可以买一个东西,然后在后面的某个城市卖掉,问最大收益.这个可以类似维护上升序列的方法在O(nlog^3n)的时间复杂度内搞定 这道题用到的一些方法: 1. 可以将有关的线段提 ...

  3. bzoj 3211 线段树

    开方操作最多进行5次就可以把出现的任何数变成1. 所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回. /***************************** ...

  4. bzoj 1018 线段树维护连通性

    本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边 ...

  5. bzoj 3212 线段树

    裸的线段树 /************************************************************** Problem: User: BLADEVIL Langua ...

  6. bzoj 2120 线段树套平衡树

    先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...

  7. bzoj 1901 线段树套平衡树+二分答案查询

    我们就建一颗线段树,线段树的每一个节点都是一颗平衡树,对于每个询问来说,我们就二分答案, 查询每个二分到的mid在这个区间里的rank,然后就行了 /************************* ...

  8. BZOJ 1012 线段树||单调队列

    非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...

  9. BZOJ 3681 线段树合并+网络流

    思路: 暴力建图有n*m条边 考虑怎么优化 (那就只能加个线段树了呗) 然后我就不会写了..... 抄了一波题解 //By SiriusRen #include <bits/stdc++.h&g ...

  10. BZOJ 4756 线段树合并(线段树)

    思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusR ...

随机推荐

  1. 使用pidstat查看进程资源使用情况

    简介 pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存.设备IO.任务切换.线程等.pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上 ...

  2. 三种空格unicode(\u00A0,\u0020,\u3000)表示的区别

    1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ; 2.半角空格(英文符号)\u0020,代码中常用的; 3.全角空格(中文 ...

  3. mysql 数据操作 单表查询 having 过滤

    SELECT 字段1,字段2... FROM 库名.表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数 1.首先找到表 库.表 ...

  4. python 面向对象· self 讲解

    self就是参数 以形参形式 5.self是什么鬼? self是一个python自动会给传值的参数 那个对象执行方法,self就是谁. obj1.fetch('selec...') self=obj1 ...

  5. CSS伪代码

    /*在p之后插入我是好人*/ p.first:after { content: "好人" } /*在p之前插入亲爱的朋友men*/ p:before { content: &quo ...

  6. Mysql5.7.10新加用户

    INSERT INTO mysql.user(HOST,USER,authentication_string,ssl_cipher,x509_issuer,x509_subject,select_pr ...

  7. python多线程为什么不能利用多核cpu

    GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题.运行下面这段 python 程序,CPU 占用率是多少? # 请勿在工作 ...

  8. java序列化与反序列化(转)

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  9. HIVE: 自定义TextInputFormat (旧版MapReduceAPI ok, 新版MapReduceAPI实现有BUG?)

    我们的输入文件 hello0, 内容如下: xiaowang 28 shanghai@_@zhangsan 38 beijing@_@someone 100 unknown 逻辑上有3条记录, 它们以 ...

  10. 微信JS支付代码_前端调用微信支付接口

    转自:http://dditblog.com/itshare_553.html 跟大家分享一段微信支付的js代码片段.V3版的微信支付没有paySignKey参数.基本上是直接复制就可以使用了.改一改 ...