洛谷 2023 [AHOI2009]维护序列
洛谷 2023 [AHOI2009]维护序列

这个题也是一道经典的线段树模版(其实洛谷的模版二改一下输入顺序就能AC),其中包括区间乘法修改、区间加法修改、区间查询三个操作。
线段树的基本操作就不再赘述了,建树,查询,修改,都比较简单,我们可以为两种操作的懒惰标记申请两个变量来记录,这道题的主要难点是down操作和两种修改的优先级问题。
这两个问题其实就是一回事:首先当我们下推标记时,如果该点加法标记不为0且乘法标记不为1(乘法标记初始化为1),那我们应该先推哪个标记呢?
实际上我们应该先推位置靠前(也就是比较早输入)的运算,可是运用懒惰标记后,我们是难以判断那个运算输入的更早。
有一种解决方法就是在每次乘法修改时,将对应位置的加法懒惰标记乘以修改值。这样我们保证了每次下推标记时必然是乘法优先。
if(tree[u].l>=x&&tree[u].r<=y)
{
tree[u].w*=c;
tree[u].w%=mod;
tree[u].mu=(tree[u].mu*c)%mod;
tree[u].ad=(tree[u].ad*c)%mod;
return;
}
这里的模运算的性质:
((a*b) % p * c)% p = (a * (b*c) % p) % p
(a * b) % p = (b * a) % p
我们可以随时对程序里的标记和值做模运算。
而下推标记时,我们只要保证乘法优先,就可以轻松打出代码:
void down(int u)
{
tree[u<<].w=(tree[u<<].w*tree[u].mu%mod+tree[u].ad*(tree[u<<].r-tree[u<<].l+)%mod)%mod;
tree[u<<|].w=(tree[u<<|].w*tree[u].mu%mod+tree[u].ad*(tree[u<<|].r-tree[u<<|].l+)%mod)%mod;
tree[u<<].mu=tree[u].mu*tree[u<<].mu%mod;
tree[u<<|].mu=tree[u].mu*tree[u<<|].mu%mod;
tree[u<<].ad=(tree[u].ad+tree[u<<].ad*tree[u].mu)%mod; //下推时加法标记也要做乘法运算
tree[u<<|].ad=(tree[u].ad+tree[u<<|].ad*tree[u].mu)%mod;
tree[u].ad=; //清空标记
tree[u].mu=;
}
下附完整AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=;
typedef long long ll; struct segtree{
int l;
int r;
ll w;
ll ad;
ll mu;
}tree[MAXN<<]; int n,m,q,x,y; ll mod,c,ans; ll read()
{
ll x=;
int k=;
char c=getchar();
while(c>''||c<'')
{
if(c=='-') k=-;
c=getchar();
}
while(c<=''&&c>='')
x=x*+c-'',
c=getchar();
return k*x;
} void build(int u,int l,int r)
{
tree[u].l=l;
tree[u].r=r;
tree[u].ad=;
tree[u].mu=;
if(l==r)
{
tree[u].w=read()%mod;
return;
}
int mid=(l+r)>>;
build(u<<,l,mid);
build(u<<|,mid+,r);
tree[u].w=(tree[u<<].w+tree[u<<|].w)%mod;
return;
} void down(int u)
{
tree[u<<].w=(tree[u<<].w*tree[u].mu%mod+tree[u].ad*(tree[u<<].r-tree[u<<].l+)%mod)%mod;
tree[u<<|].w=(tree[u<<|].w*tree[u].mu%mod+tree[u].ad*(tree[u<<|].r-tree[u<<|].l+)%mod)%mod;
tree[u<<].mu=tree[u].mu*tree[u<<].mu%mod;
tree[u<<|].mu=tree[u].mu*tree[u<<|].mu%mod;
tree[u<<].ad=(tree[u].ad+tree[u<<].ad*tree[u].mu)%mod;
tree[u<<|].ad=(tree[u].ad+tree[u<<|].ad*tree[u].mu)%mod;
tree[u].ad=;
tree[u].mu=;
} void query(int u)
{
if(tree[u].l>=x&&tree[u].r<=y)
{
ans=(ans+tree[u].w)%mod;
return;
}
down(u);
int mid=(tree[u].l+tree[u].r)>>;
if(x<=mid) query(u<<);
if(y>mid) query(u<<|);
return;
} void mul(int u)
{
if(tree[u].l>=x&&tree[u].r<=y)
{
tree[u].w*=c;
tree[u].w%=mod;
tree[u].mu=(tree[u].mu*c)%mod;
tree[u].ad=(tree[u].ad*c)%mod;
return;
}
down(u);
int mid=(tree[u].l+tree[u].r)>>;
if(x<=mid) mul(u<<);
if(y>mid) mul(u<<|);
tree[u].w=(tree[u<<].w+tree[u<<|].w)%mod;
return;
} void add(int u)
{
if(tree[u].l>=x&&tree[u].r<=y)
{
tree[u].ad=(tree[u].ad+c)%mod;
tree[u].w+=(tree[u].r-tree[u].l+)*c;
tree[u].w%=mod;
return;
}
down(u);
int mid=(tree[u].l+tree[u].r)>>;
if(x<=mid) add(u<<);
if(y>mid) add(u<<|);
tree[u].w=(tree[u<<].w+tree[u<<|].w)%mod;
return;
} int main()
{
n=read();
mod=read();
build(,,n);
m=read();
for(int i=;i<=m;++i)
{
q=read();
x=read();
y=read();
if(q==)
{
c=read();
mul();
}
if(q==)
{
c=read();
add();
}
if(q==)
{
ans=;
query();
printf("%lld\n",ans%mod);
}
}
return 0;
}
洛谷 2023 [AHOI2009]维护序列的更多相关文章
- 洛谷P2023 [AHOI2009]维护序列(线段树区间更新,区间查询)
洛谷P2023 [AHOI2009]维护序列 区间修改 当我们要修改一个区间时,要保证 \(ax+b\) 的形式,即先乘后加的形式.当将区间乘以一个数 \(k\) 时,原来的区间和为 \(ax+b\) ...
- [洛谷P2023] [AHOI2009]维护序列
洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...
- 洛谷 P2023 [AHOI2009]维护序列
P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中 ...
- 洛谷 P2023 [AHOI2009]维护序列 题解
P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中 ...
- 【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
洛谷P2023:https://www.luogu.org/problemnew/show/P2023 思路 需要2个Lazy-Tag 一个表示加的 一个表示乘的 需要先计算乘法 再计算加法 来自你谷 ...
- 洛谷 P2023 [AHOI2009]维护序列 || 线段树加法和乘法运算
原理倒是非常简单.设原数为x,加法的lazytag为b,乘法的lazytag为a,操作数为c,那么原式为ax+b,乘上c后(ax+b)c=(ac)*x+b*c,加上c后(ax+b)+c=ax+(b+c ...
- [Luogu 2023] AHOI2009 维护序列
[Luogu 2023] AHOI2009 维护序列 恕我冒昧这和线段树模板二有个琴梨区别? #include <cstdio> int n,m; long long p; class S ...
- 洛谷P3373 【模板】线段树 2 && P2023 [AHOI2009]维护序列——题解
题目传送: P3373 [模板]线段树 2 P2023 [AHOI2009]维护序列 该题较传统线段树模板相比多了一个区间乘的操作.一提到线段树的区间维护问题,就自然想到了“懒标记”:为了降低时间复 ...
- BZOJ_1798_[AHOI2009]维护序列_线段树
BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...
随机推荐
- Sass 愿景
在最近的一个 CSS 见面会上,我向与会者提问,“有人会在日常的工作流中使用 Sass 吗?”回答结果压倒性的表示肯定——保守谨慎地使用 Sass 已经成为过去式.Sass 正迅速成长为编写 CSS ...
- 在线获取键盘按键值(ascii码)工具
在线获取键盘按键值(ascii码)工具 http://www.bejson.com/othertools/keycodes/ 可以根据输入的值获取对应的键盘ascii码值
- [TCP/IP]TCP的三次握手和四次挥手
概述 总结一下TCP中3次握手过程,以及其原生的缺陷 引起的SYN Flood的介绍 1.TCP连接建立--三次握手 几个概念: seq:序号,占4个字节,范围[0,4284967296],由于TCP ...
- Codeforces 27D(二分染色)
要点 将边作为染色,如果交叉则异色 #include <cstdio> #include <algorithm> #include <functional> usi ...
- II play with GG(思维规律)
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 IG won the S champion ...
- 2017ACM/ICPC广西邀请赛 CS Course
题意:删除指定数字,求剩下数字的与或非值 解法:保存一下前缀和后缀 #include <iostream> #include <stdio.h> #include <ve ...
- 关系型数据库---MySQL---索引
1.概述 参考资料:http://blog.codinglabs.org/articles/theory-of-mysql-index.html 1.1 索引的本质: MySQL官方对索引的定义:索引 ...
- TVS选型
与保护器件并联使用的电压型保护器件,速度快,冲击脉冲功率高.正常高阻抗,超过击穿电压后导通将两端电压钳位在VC(即被保护的电压级别) 命名规则SMAJ/BJ/CJ/DJ分别表示不同的脉冲功率为400W ...
- POJ 1015 Jury Compromise dp分组
第一次做dp分组的问题,百度的~~ http://poj.org/problem?id=1015 题目大意:在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定.陪审团是由法官从公众中挑选的.先随机挑 ...
- (转)生产环境常见的HTTP状态码列表(老男孩整理)
生产环境常见的HTTP状态码列表(老男孩整理) 原文:http://blog.51cto.com/oldboy/716294 ##################################### ...