洛谷 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]维护序列的更多相关文章

  1. 洛谷P2023 [AHOI2009]维护序列(线段树区间更新,区间查询)

    洛谷P2023 [AHOI2009]维护序列 区间修改 当我们要修改一个区间时,要保证 \(ax+b\) 的形式,即先乘后加的形式.当将区间乘以一个数 \(k\) 时,原来的区间和为 \(ax+b\) ...

  2. [洛谷P2023] [AHOI2009]维护序列

    洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...

  3. 洛谷 P2023 [AHOI2009]维护序列

    P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中 ...

  4. 洛谷 P2023 [AHOI2009]维护序列 题解

    P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中 ...

  5. 【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)

    洛谷P2023:https://www.luogu.org/problemnew/show/P2023 思路 需要2个Lazy-Tag 一个表示加的 一个表示乘的 需要先计算乘法 再计算加法 来自你谷 ...

  6. 洛谷 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 ...

  7. [Luogu 2023] AHOI2009 维护序列

    [Luogu 2023] AHOI2009 维护序列 恕我冒昧这和线段树模板二有个琴梨区别? #include <cstdio> int n,m; long long p; class S ...

  8. 洛谷P3373 【模板】线段树 2 && P2023 [AHOI2009]维护序列——题解

    题目传送: P3373 [模板]线段树 2  P2023 [AHOI2009]维护序列 该题较传统线段树模板相比多了一个区间乘的操作.一提到线段树的区间维护问题,就自然想到了“懒标记”:为了降低时间复 ...

  9. BZOJ_1798_[AHOI2009]维护序列_线段树

    BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...

随机推荐

  1. 如何在JMeter中使用ForEach控制器

    Jmeter中的ForEach Controller遍历变量数组. 在这个JMeter教程中,我们将使用ForEach控制器循环访问JSON数组. 有时我们需要解析响应并提取某些信息.例如,在测试AP ...

  2. hdu5884

    #include <cstdio> #include <queue> #include <algorithm> #include <string.h> ...

  3. WebApi迁移ASP.NET Core2.0

    WebApi迁移ASP.NET Core2.0 一步一步带你做WebApi迁移ASP.NET Core2.0   随着ASP.NET Core 2.0发布之后,原先运行在Windows IIS中的AS ...

  4. 牛客网Java刷题知识点之什么是匿名内部类、匿名内部类的使用原则、匿名内部类初始化、匿名内部类使用的形参为何要为final 和 案例

    不多说,直接上干货! 什么是匿名内部类 匿名内部类就是没有名字的内部类. 不使用关键字class . extends .implements 没有构造函数 必须继承其他类或实现其他接口 正因为没有名字 ...

  5. 基于 opencv图像去噪

                       -------------------开通头条号-------------------- 实验名称 图像去噪 实验目的 1.掌握算术均值滤波器.几何均值滤波器.谐 ...

  6. left join \ right join \ inner join 详解

    left join 和 left outer join 的区别 通俗的讲:   A   left   join   B   的连接的记录数与A表的记录数同   A   right   join   B ...

  7. MyBatis配置文件之properties属性

    MyBatis提供3个方式使用properties: 1.property子元素. 2.properties文件. 3.程序代码传递. properties属性系给系统配置一些运行参数,一般放在XML ...

  8. 链接服务器"(null)"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 "Cannot start more transactions on this session."

    开发同事反馈一个SQL Server存储过程执行的时候,报"链接服务器"(null)"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 ...

  9. HttpRunner环境搭建

    官方文档地址:http://cn.httprunner.org/官方源码地址:https://github.com/HttpRunner/HttpRunner HttpRunner 是一款面向 HTT ...

  10. Codevs 1860 最大数

    题目描述 Description 设有n个正整数(n≤20),将它们联接成一排,组成一个最大的多位整数. 输入描述 Input Description 第一行一个正整数n. 第二行n个正整数,空格隔开 ...