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 first---放置在外存中的文件读取
照样以登录案例举例: 第一步:界面绘制:跟之前写过的一个案例一样 第二步:逻辑代码 public class MainActivity extends Activity { //定义全局变量 p ...
- [问题2014A01] 复旦高等代数 I(14级)每周一题(第三教学周)
[问题2014A01] 试求下列 \(n\) 阶行列式的值: \[ |A|=\begin{vmatrix} 1 & x_1(x_1-a) & x_1^2(x_1-a) & \ ...
- [问题2014S10] 复旦高等代数II(13级)每周一题(第十教学周)
[问题2014S10] 设 \(A,B\) 为 \(n\) 阶方阵, 证明: \(AB\) 与 \(BA\) 相似的充分必要条件是 \[\mathrm{rank}\big((AB)^i\big)=\ ...
- Android pulltorefresh使用
pulltorefresh插件可以轻松实现上拉下拉刷新,github.com上直接搜索进行下载. 布局文件: <RelativeLayout xmlns:android="http:/ ...
- 【转】Vim十大必备插件
[转]Vim十大必备插件 转自:http://my.oschina.net/zhoukuo/blog/336315 Taglist taglist是一个用于显示定位程序中各种符号的插件,例如宏定义.变 ...
- C语言语法之运算符及优先级
注:该内容整理自以下链接. http://blog.csdn.net/huangblog/article/details/8271791 表:C语言运算符及优先级 优先级 运算符 名称或含义 使用形式 ...
- SQL Server去掉字段内的双引号
今天在客户处遇到一个问题,用powershell抓取出的数据插入SQL中后每个字段都会自动带双引号“”如下: 现在想将此双引号去掉,用下面语句即可: insert into #A select SUB ...
- Bitmap旋转方法
最近在做一个ORC图片解析的功能,要求解析出数字 但是发现他解析只能解析横着的图片,然后我拍照的时候拍的是竖直照片,当然你也可以去旋转照相机的屏幕 但是我这里为了方便选择的是竖直拍出来 然后,旋转下咯 ...
- MVC4中的Display Mode简介
本文地址:http://www.cnblogs.com/egger/p/3400076.html 欢迎转载 ,请保留此链接๑•́ ₃•̀๑! 今天学习MVC4时,看到一个不错的特性"vie ...
- JavaWeb基础: ServletConfig
基本概念 ServletConfig用于配置Servlet的参数:在Servlet的配置文件中,可以使用一个或者是多个<init-param> 标签为Servlet配置一些初始化参数.当有 ...