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 < ...
随机推荐
- 模板引擎:ArtTemplate 使用入门和简单的使用
下载地址:https://github.com/aui/artTemplate 快速上手请参考:https://github.com/aui/artTemplate 通过阅读artTemplate原文 ...
- zigbee学习之路(十):串口(接收)
一.前言 上次我们学习了串口的发送,今天我们要学习串口的接收,要实现的功能是接收电脑发来的数据,控制LED 灯闪烁,而且将收到的数据发回给电脑显示出来.而且要采用不占用cpu资源的中断. 二原理与分析 ...
- php中的访问修饰符 private、protected、public的作用范围
1. private 只能在类内部使用 2. protected 可以在类内部和继承类里使用.类外部不能使用[即实例化后的对象无法调用] 3. public 全部范围适用. 4.子类复写父类中的方法时 ...
- 利用excel拆分数据
要求:将sheet1中的数据按照公司名称拆分到不同的工作表 使用VBA: 1:打开sheet1的查看代码 2:运行 ·········································· ...
- sqlloader导出数据和导入数据
分类: Oracle 忙了一天终于把sqlloader导出数据和导入数据弄清楚了,累死俺了... 这个总结主要分为三个大部分,第一部分(实例,主要分两步),第二部分(参数小总结),第三部分(完全参数总 ...
- nodejs 访问mysql
安装 $ npm install mysql 简介 这个一个mysql的nodejs版本的驱动,是用JavaScript来编写的.不需要编译 这儿有个例子来示范如何使用: var mysql = re ...
- linux详细redis安装和php中redis扩展
第一部分:安装redis 希望将redis安装到此目录 1 /usr/local/redis 希望将安装包下载到此目录 1 /usr/local/src 那么安装过程指令如下: 1 2 3 4 5 6 ...
- Greenplum 在Linux下的安装
1.实验环境 1.1.硬件环境 Oracle VM VirtualBox虚拟机软件:三台Linux虚拟机:Centos 6.5:数据库:greenplum-db-4.3.9.1-build-1-rhe ...
- seek指针大文件上传
package mainimport ( // "bufio" "fmt" "github.com/axgle/mahonia&qu ...
- jquery 判断元素是否隐藏
$(select).is(":hidden") 返回 true/false