洛谷 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. 用SqlDataAdapter与datagridview配合实现快速CRUD

    private void btnSave_Click(object sender, EventArgs e) { //把DataGridView的修改的数据保存到数据库中去. string connS ...

  2. CC20:高度最小的BST

    题目 对于一个元素各不相同且按升序排列的有序序列,请编写一个算法,创建一棵高度最小的二叉查找树. 给定一个有序序列int[] vals,请返回创建的二叉查找树的高度. 解法 这道题感觉如果没有创建树的 ...

  3. edge 浏览器自动识别电话号码解问题解决方法

    解决方案:再head中加上:  <meta name="format-detection" content="telephone=no"> 

  4. 优化MyEclipse编译速度慢的问题

    转载大神的 https://www.cnblogs.com/luxd/p/5999217.html

  5. CoreCLR

    CoreCLR 在这篇中我将讲述GC Collector内部的实现, 这是CoreCLR中除了JIT以外最复杂部分,下面一些概念目前尚未有公开的文档和书籍讲到. 为了分析这部分我花了一个多月的时间,期 ...

  6. var type = $('#<%=DropDownListRateType.ClientID %>').val();DropDownListRateType.ClientID是什么意思

    <%=DropDownListRateType.ClientID %>这个是C#绑定服务器控件在客户端ID, 比如你的DropDownListRateType你定义一个id,如果你用了模板 ...

  7. 洛谷P2606 [ZJOI2010]排列计数(组合数 dp)

    题意 题目链接 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案 ...

  8. Struts功能详解 ——ActionServlet

    ActionServlet类是Struts框架的内置核心控制器组件,它继承了javax.servlet.http.HttpServlet类.Struts的启动通常从 加载ActionServlet开始 ...

  9. SqlServer中提示和报错信息的翻译

    有时候遇到SqlServer一些报错需要上网查找解决方法,一些比较生僻的问题汉语搜索往往得不到想要的,就要使用英文在外网搜索.之前都是自己尝试翻译,或者使用错误码,或者找个英文版的数据库重现问题.有时 ...

  10. 转载 - 浅析我曾遇到的几个便宜VPS服务器

    本文来自:http://www.jianshu.com/p/7d8cfa87fa32 有些时候可能并不是我们工作和业务的需要,但是网上就是这么的邪门,如果看到便宜的衣服不去购买深怕自己吃亏.所以每年的 ...