我原来准备做方差的。。

结果发现不会维护两个标记。。

就是操作变成一个 a*x+b ,每次维护a , b 即可

加的时候a=1 ,b=v

乘的时候a=v ,b=0

 #include <cstdio>
const long long Maxn=; long long a[Maxn],n,P,l,r,c,m,type;
struct Node
{
long long mul,add,sum,len;
}tree[Maxn<<]; inline void Change(long long o,long long mul,long long add)
{
tree[o].mul=(tree[o].mul*mul)%P;
tree[o].add=(tree[o].add*mul+add)%P;
tree[o].sum=(tree[o].sum*mul+tree[o].len*add)%P;
}
inline void push_down(long long o)
{
Change(o<<,tree[o].mul,tree[o].add);
Change(o<<|,tree[o].mul,tree[o].add);
tree[o].mul=; tree[o].add=;
}
inline void push_up(long long o)
{
tree[o].sum=(tree[o<<].sum+tree[o<<|].sum)%P;
tree[o].len=tree[o<<].len+tree[o<<|].len;
}
void Build(long long o,long long l,long long r)
{
tree[o].mul=; tree[o].add=;
if (l==r) {tree[o].sum=a[l]; tree[o].len=; return;}
long long mid=(l+r)>>;
Build(o<<,l,mid),Build(o<<|,mid+,r);
push_up(o);
}
void Mul(long long o,long long l,long long r,long long p,long long q,long long v)
{
if (l==p && r==q)
{
Change(o,v,);
return;
}
push_down(o);
long long mid=(l+r)>>;
if (q<=mid) Mul(o<<,l,mid,p,q,v);
if (p>=mid+) Mul(o<<|,mid+,r,p,q,v);
if (p<=mid && q>=mid+)
Mul(o<<,l,mid,p,mid,v),Mul(o<<|,mid+,r,mid+,q,v);
push_up(o);
}
void Add(long long o,long long l,long long r,long long p,long long q,long long v)
{
if (l==p && r==q)
{
Change(o,,v);
return;
}
push_down(o);
long long mid=(l+r)>>;
if (q<=mid) Add(o<<,l,mid,p,q,v);
if (p>=mid+) Add(o<<|,mid+,r,p,q,v);
if (p<=mid && q>=mid+)
Add(o<<,l,mid,p,mid,v),Add(o<<|,mid+,r,mid+,q,v);
push_up(o);
}
long long Sum(long long o,long long l,long long r,long long p,long long q)
{
if (l==p && r==q) return tree[o].sum;
long long mid=(l+r)>>;
push_down(o);
if (q<=mid) return Sum(o<<,l,mid,p,q);
if (p>=mid+) return Sum(o<<|,mid+,r,p,q);
if (p<=mid && q>=mid+)
return (Sum(o<<,l,mid,p,mid)+Sum(o<<|,mid+,r,mid+,q))%P;
}
int main()
{
// freopen("c.in","r",stdin);
scanf("%lld%lld",&n,&P);
for (long long i=;i<=n;i++) scanf("%lld",&a[i]);
Build(,,n);
scanf("%lld",&m);
for (long long i=;i<=m;i++)
{
scanf("%lld",&type);
if (type==)
{
scanf("%lld%lld%lld",&l,&r,&c);
Mul(,,n,l,r,c);
}
if (type==)
{
scanf("%lld%lld%lld",&l,&r,&c);
Add(,,n,l,r,c);
}
if (type==)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",Sum(,,n,l,r));
}
}
return ;
}

线段树

UPD:2016.6.14

突然发现好久没有写过分块了,想到这道可以分块,push_up写成push_down了..

 #include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
const LL Maxn=;
const LL Inf=0x3f3f3f3f;
LL a[Maxn],n,P,l,r,c,m,type,Block[Maxn];
struct Node
{
LL mul,add,len,sum;
}tree[Maxn]; inline void Change(LL o,LL mul,LL add)
{
tree[o].mul=(tree[o].mul*mul)%P;
tree[o].add=(tree[o].add*mul+add)%P;
tree[o].sum=(tree[o].sum*mul+tree[o].len*add)%P;
}
inline void push_down(LL o)
{
for (;Block[o]==Block[o-];o--);
for (LL i=o;Block[o]==Block[i];i++) a[i]=(a[i]*tree[Block[i]].mul+tree[Block[i]].add)%P;
tree[Block[o]].mul=,tree[Block[o]].add=;
} inline void push_up(LL o)
{
tree[Block[o]].sum=;
for (;Block[o]==Block[o-];o--);
for (LL i=o;Block[o]==Block[i];i++) tree[Block[o]].sum=(tree[Block[o]].sum+a[i])%P;
}
void Mul(LL p,LL q,LL v)
{
if (Block[p]==Block[q])
{
push_down(p);
for (LL i=p;i<=q;i++) a[i]=(a[i]*v)%P;
push_up(p);
return;
}
for (LL i=Block[p]+;i<Block[q];i++) Change(i,v,);
push_down(p),push_down(q);
for (LL i=p;Block[i]==Block[p];i++) a[i]=(a[i]*v)%P;
for (LL i=q;Block[i]==Block[q];i--) a[i]=(a[i]*v)%P;
push_up(p),push_up(q);
} void Add(LL p,LL q,LL v)
{
if (Block[p]==Block[q])
{
push_down(p);
for (LL i=p;i<=q;i++) a[i]=(a[i]+v)%P;
push_up(p);
return;
}
for (LL i=Block[p]+;i<Block[q];i++) Change(i,,v);
push_down(p),push_down(q);
for (LL i=p;Block[i]==Block[p];i++) a[i]=(a[i]+v)%P;
for (LL i=q;Block[i]==Block[q];i--) a[i]=(a[i]+v)%P;
push_up(p),push_up(q);
}
LL Sum(LL p,LL q)
{
LL ret=;
if (Block[p]==Block[q])
{
push_down(p);
for (LL i=p;i<=q;i++) ret=(ret+a[i])%P;
return ret;
}
for (LL i=Block[p]+;i<Block[q];i++) ret=(ret+tree[i].sum)%P;
push_down(p),push_down(q);
for (LL i=p;Block[i]==Block[p];i++) ret=(ret+a[i])%P;
for (LL i=q;Block[i]==Block[q];i--) ret=(ret+a[i])%P;
return ret;
}
int main()
{
scanf("%lld%lld",&n,&P);
for (LL i=;i<=n;i++) scanf("%lld",&a[i]),a[i]%=P;
LL pos=(LL)sqrt(n);
for (LL i=;i<=n;i++) Block[i]=(i-)/pos+;
memset(tree,,sizeof(tree));
for (LL i=;i<=n;i++) tree[Block[i]].len++;
for (LL i=;i<=n;i++) tree[Block[i]].mul=;
for (LL i=;i<=n;i++) tree[Block[i]].sum=(tree[Block[i]].sum+a[i])%P; scanf("%lld",&m);
for (LL i=;i<=m;i++)
{
scanf("%lld",&type);
if (type==)
{
scanf("%lld%lld%lld",&l,&r,&c);
Mul(l,r,c);
}
if (type==)
{
scanf("%lld%lld%lld",&l,&r,&c);
Add(l,r,c);
}
if (type==)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",Sum(l,r));
}
}
return ;
}

分块

BZOJ 1798 (线段树||分块)的标记合并的更多相关文章

  1. bzoj 1798 线段树

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 7163  Solved: 2587[Submit ...

  2. 洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)

    题面传送门 首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times ...

  3. codeforces Good bye 2016 E 线段树维护dp区间合并

    codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...

  4. SPOJ - GSS1 —— 线段树 (结点信息合并)

    题目链接:https://vjudge.net/problem/SPOJ-GSS1 GSS1 - Can you answer these queries I #tree You are given ...

  5. BZOJ 3110 线段树套线段树

    思路: 外围一个权值线段树 里面是个区间线段树 搞一个标记永久化 //By SiriusRen #include <cstdio> #include <cstring> #in ...

  6. bzoj 3585 mex - 线段树 - 分块 - 莫队算法

    Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问 ...

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

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

  8. BZOJ 2212线段树的合并

    借鉴(抄)了一下题解-- 线段树合并的裸题吧- //By SiriusRen #include <cstdio> #include <cstring> #include < ...

  9. BZOJ 2733 线段树的合并 并查集

    思路: 1.线段树合并(nlogn的) 2.splay+启发式合并 线段树合并比较好写 我手懒 //By SiriusRen #include <cstdio> #include < ...

随机推荐

  1. 关于cookie的文章(cookie与session机制)

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  2. 第四章:管道与FIFO

    4.1:概述 管道是最初的Unix IPC形式,可追溯到1973年的Unix第三版.尽管对于许多操作来说很有用,但它们的根本局限在于没有名字,从而只能由亲缘关系的进程使用.这一点随FIFO的加入得改正 ...

  3. mysql之常用操作

    1. 数据库介绍 什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据.我们也可以将数 ...

  4. javascript 常用实用函数。。。。。。

    javascript 正则表达式 1.获取屏幕大小尺寸 /* 获取屏幕大小尺寸 */ var getScreen = function () { var screen = { width: 0, he ...

  5. linux环境下安装mysql数据库遇到的问题

    总结一句话: 安装完mysql数据库记得授权远程登录.   坑的现象: ERROR 1045 (28000): Access denied for user 'guoxp'@'localhost' ( ...

  6. 我的android学习经历33

    在Activity中添加菜单 1.在res目录下新建文件夹menu 右击res,选择new->Folder,Folder name写为menu 2.在新建的menu目录下新建一个xml文件 右击 ...

  7. Linux基本操作1 - 设备操作

    Linux开发的过程中,肯定会使用到很多设备,所以对设备的挂载卸载是一个很基本的操作. Linux对设备的默认定义如下: 一.Linux中的硬件设备号     设 备          设 备 号   ...

  8. XML与JSON的转换

    -(void)test {          //XML文本范例     NSString *testXMLString = @"Cake0.55RegularChocolateBluebe ...

  9. 深入浅出设计模式——抽象工厂模式(Abstract Factory)

    模式动机在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法.但是有时候我们需要一个工厂可 ...

  10. 《BI那点儿事》数据流转换——导入列、导出列

    导入列: 导入列例子现在来做一个例子:创建路径D:\Pictures随便在路径D:\Pictures中粘贴4个比较小的图像文件命名为01.png.02.png.03.png.04.png在路径D:\P ...