BZOJ 1798 (线段树||分块)的标记合并
我原来准备做方差的。。
结果发现不会维护两个标记。。
就是操作变成一个 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 (线段树||分块)的标记合并的更多相关文章
- bzoj 1798 线段树
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 7163 Solved: 2587[Submit ...
- 洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)
题面传送门 首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times ...
- codeforces Good bye 2016 E 线段树维护dp区间合并
codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...
- SPOJ - GSS1 —— 线段树 (结点信息合并)
题目链接:https://vjudge.net/problem/SPOJ-GSS1 GSS1 - Can you answer these queries I #tree You are given ...
- BZOJ 3110 线段树套线段树
思路: 外围一个权值线段树 里面是个区间线段树 搞一个标记永久化 //By SiriusRen #include <cstdio> #include <cstring> #in ...
- bzoj 3585 mex - 线段树 - 分块 - 莫队算法
Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问 ...
- BZOJ 4756 线段树合并(线段树)
思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusR ...
- BZOJ 2212线段树的合并
借鉴(抄)了一下题解-- 线段树合并的裸题吧- //By SiriusRen #include <cstdio> #include <cstring> #include < ...
- BZOJ 2733 线段树的合并 并查集
思路: 1.线段树合并(nlogn的) 2.splay+启发式合并 线段树合并比较好写 我手懒 //By SiriusRen #include <cstdio> #include < ...
随机推荐
- Android开发之MediaRecorder类详解
MediaRecorder类介绍: MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频,摄像头采集图片信息. MediaRecorder主要函 ...
- css回忆(一)
1.css的引入方式: a) 在head部分加入<link rel="stylesheet" type="text/css" href="my ...
- SQL2008游标
最近让写一个自动生成数据的存储过程,其中会遍历表中数据并做出相应处理,因为数据量不算太大所以使用到了游标,初识游标遇到几个小问题,所以来和大家一起分享一下: 使用游标的五个步骤: 1.声明游标 语法: ...
- 怎样在excel中添加下拉列表框
用excel2013打开要编辑的工作表,例子是一个班级名单,可以看到政治面貌目前还没有填写 接着我们找一个空白处,依次写入政治面貌的可能选项: 群众.共青团员 然后选中“政治面貌”这一列,点击 ...
- 转:[置顶] 从头到尾彻底理解KMP(2014年8月22日版)
[置顶] 从头到尾彻底理解KMP(2014年8月22日版)
- CSS和Js样式属性的对照关系
注意:1.在使用js时,如newTD.style.paddingLeft="200";(错误),正确生效的写法是newTD.style.paddingLeft="200p ...
- iframe 子页面获取父页面的元素并且控制样式
父页面的代码 <div id="div5" style="position:relative;height:500px;"> ...
- linux笔记:shell基础-bash变量
shell变量设置规则: 变量的分类: 环境变量的设置: 系统常见环境变量: 位置参数变量(用来接收脚本的参数): 预定义变量: 接收键盘输入(将键盘输入的值赋值给变量名): 用declare声明变量 ...
- 基础向量运算-2D镜面反射
如图M为镜面,A为入射光,B为反射光,已知A与M的向量坐标,求B的向量表示. 我们添加辅助向量C. 有以下性质. B = 2 * C - A. [1] |C| = |A| * cos(alpah).A ...
- 检测当前运行环境——移动端与PC端。
方法1: $(function checkBrowser(){ var browser={ versions:function(){ var u = navigator.userAgent, app ...