P3373 【模板】线段树 2

题目描述

如题,已知一个数列,你需要进行下面三种操作:

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和

线段树维护区间乘法

1.如何修改?

  一个数去乘区间里的每一个数,那么这个区间的和会乘以这个数,需要乘法标记,初始化为1,乘法标记要乘以这个数,来下传到他的子树中,即更新他的子区间,当然,他的加法标记也要乘以这个数。

2.如何更新?

他子树的值=它的乘法标记*它子树的值+他子树的区间长度*它的加法标记

乘法标记更新,加法标记更新

某位大佬的线段树

#include<bits/stdc++.h>
#define N 4000000
#define LL long long
#define RE register
#define IN inline using namespace std; IN void in(LL &x){
RE char c=getchar();x=;int f=;
while(!isdigit(c)) {if(c=='-') f=-;c=getchar();}
while(isdigit(c)){x=x*+c-'';c=getchar();}
x*=f;
} /*
1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和
*/ LL n,m,X,ans,p;
struct node{
LL l,r,w,f,mul;
}e[N]; IN void build(LL k,LL l,LL r){
e[k].l=l;e[k].r=r;e[k].mul=;e[k].f=;
if(l==r){
in(e[k].w);return;
}LL mid=(l+r)/;
build(k*,l,mid);build(k*+,mid+,r);
e[k].w=(e[k*].w+e[k*+].w)%p;
} IN void down(LL k){
LL mu=e[k].mul,ll=e[k].l,rr=e[k].r,mid=(ll+rr)/;
e[k*].w=(e[k*].w*mu+e[k].f*(mid-ll+))%p;
e[k*+].w=(e[k*+].w*mu+e[k].f*(rr-mid))%p; e[k*].mul=(e[k*].mul*mu)%p;
e[k*+].mul=(e[k*+].mul*mu)%p; e[k*].f=(e[k*].f*mu+e[k].f)%p;
e[k*+].f=(e[k*+].f*mu+e[k].f)%p; e[k].f=;e[k].mul=;
} IN void mull(LL k,LL l,LL r){
LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/;
if(ll>=l&&rr<=r){
e[k].w=(e[k].w*X)%p;
e[k].mul=(e[k].mul*X)%p;
e[k].f=(e[k].f*X)%p;
return ;
}if(e[k].f!=||e[k].mul!=) down(k);
if(l<=mid) mull(k*,l,r);if(r>mid) mull(k*+,l,r);
e[k].w=(e[k*].w+e[k*+].w)%p;
} IN void change_LLerval(LL k,LL l,LL r){
LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/;
if(ll>=l&&rr<=r){
e[k].f=(e[k].f+X)%p;
e[k].w=((rr-ll+)*X+e[k].w)%p;return ;
}if(e[k].f!=||e[k].mul!=) down(k);
if(l<=mid) change_LLerval(k*,l,r);if(r>mid) change_LLerval(k*+,l,r);
e[k].w=(e[k*].w+e[k*+].w)%p;
} IN void ask_LLerval(LL k,LL l,LL r){
LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/;
if(ll>=l&&rr<=r){
ans=(e[k].w+ans)%p;return;
}if(e[k].f!=||e[k].mul!=) down(k);
if(l<=mid) ask_LLerval(k*,l,r);if(r>mid) ask_LLerval(k*+,l,r);
e[k].w=(e[k*].w+e[k*+].w)%p;
} int main()
{
in(n);in(m);in(p);
build(,,n);
while(m--){
LL tp,x,y,k;
in(tp);in(x);in(y);
if(tp!=) in(k);
if(tp==) X=k,mull(,x,y);
else if(tp==) X=k,change_LLerval(,x,y);
else{
ans=,ask_LLerval(,x,y);
printf("%d\n",ans);
}
}return ;
}

B数据结构

链接:https://www.nowcoder.com/acm/contest/200/B
来源:牛客网

qn姐姐最好了~
qn姐姐给你了一个长度为n的序列还有m次操作让你玩,
1 l r 询问区间[l,r]内的元素和
2 l r 询问区间[l,r]内的元素的平方 和
3 l r x 将区间[l,r]内的每一个元素都乘上x
4 l r x 将区间[l,r]内的每一个元素都加上x

维护区间平方和的值。其他类似吧。。

 
#include<bits/stdc++.h>

#define N int(1e6)
#define LL long long using namespace std; void in(LL &x) {
register char c=getchar();
x=;
int f=;
while(!isdigit(c)) {
if(c=='-') f=-;
c=getchar();
}
while(isdigit(c)) {
x=x*+c-'';
c=getchar();
}
x*=f;
} struct node{
LL l,r,w1,w2,mul,ad;
}tr[N]; inline void push_up(int k){
tr[k].w1=tr[k<<].w1+tr[k<<|].w1;
tr[k].w2=tr[k<<].w2+tr[k<<|].w2;
} inline void build(LL k,LL l,LL r){
tr[k].l=l,tr[k].r=r,tr[k].mul=;
if(l==r) {
in(tr[k].w1);
tr[k].w2=tr[k].w1*tr[k].w1;
return;
}
LL mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
push_up(k);
} inline void push_down(LL k){
tr[k<<].w2=tr[k<<].w2*tr[k].mul*tr[k].mul+tr[k<<].w1**tr[k].ad+(tr[k<<].r-tr[k<<].l+)*tr[k].ad*tr[k].ad;
tr[k<<].w1=tr[k<<].w1*tr[k].mul+tr[k].ad*(tr[k<<].r-tr[k<<].l+);
tr[k<<].ad+=tr[k].ad;
tr[k<<].mul*=tr[k].mul; tr[k<<|].w2=tr[k<<|].w2*tr[k].mul*tr[k].mul+tr[k<<|].w1**tr[k].ad+(tr[k<<|].r-tr[k<<|].l+)*tr[k].ad*tr[k].ad;
tr[k<<|].w1=tr[k<<|].w1*tr[k].mul+tr[k].ad*(tr[k<<|].r-tr[k<<|].l+);
tr[k<<|].ad+=tr[k].ad;
tr[k<<|].mul*=tr[k].mul; tr[k].ad=,tr[k].mul=;
} inline void update_mul(LL k,LL L,LL R,LL w){
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>;
if(l>=L&&r<=R){
tr[k].mul*=w;
tr[k].ad*=w;
tr[k].w2=w*w*tr[k].w2;
tr[k].w1=w*tr[k].w1;
return;
}
push_down(k);
if(L<=mid) update_mul(k<<,L,R,w);
if(R>mid) update_mul(k<<|,L,R,w);
push_up(k);
} inline void update(LL k,LL L,LL R,LL w){
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>;
if(l>=L&&r<=R){
tr[k].w2+=tr[k].w1**w+(r-l+)*w*w;
tr[k].w1+=w*(r-l+);
tr[k].ad+=w;
return;
}
push_down(k);
if(L<=mid) update(k<<,L,R,w);
if(R>mid) update(k<<|,L,R,w);
push_up(k);
} LL query1(LL k,LL L,LL R){
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>;
if(l>=L&&r<=R) return tr[k].w1;
push_down(k);
LL an=;
if(L<=mid) an+=query1(k<<,L,R);
if(R>mid) an+=query1(k<<|,L,R);
push_up(k);
return an;
} LL query2(LL k,LL L,LL R){
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>;
if(l>=L&&r<=R) return tr[k].w2;
push_down(k);
LL an=;
if(L<=mid) an+=query2(k<<,L,R);
if(R>mid) an+=query2(k<<|,L,R);
push_up(k);
return an;
} LL n,m; int main()
{
in(n),in(m);
build(,,n);
for(LL opt,l,r,w,i=;i<=m;i++){
in(opt),in(l),in(r);
if(opt==){
printf("%lld\n",query1(,l,r));
}
if(opt==){
printf("%lld\n",query2(,l,r));
}
if(opt==){
in(w);
update_mul(,l,r,w);
}
if(opt==){
in(w);
update(,l,r,w);
}
}
return ;
}

洛谷——P3373 【模板】线段树 2&& B 数据结构的更多相关文章

  1. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  2. 线段树_区间加乘(洛谷P3373模板)

    题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字 ...

  3. 洛谷 - P1198 - 最大数 - 线段树

    https://www.luogu.org/problemnew/show/P1198 要问区间最大值,肯定是要用线段树的,不能用树状数组.(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊 ...

  4. 洛谷 P2391 白雪皑皑 线段树+优化

    题目描述: 现在有 \(N\) 片雪花排成一列. Pty 要对雪花进行$ M $次染色操作,第 \(i\)次染色操作中,把\((i*p+q)%N+1\) 片雪花和第\((i*q+p)%N+1\)片雪花 ...

  5. 【洛谷】【线段树】P1471 方差

    [题目背景:] 滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西. [题目描述:] 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差 ...

  6. 【洛谷】【线段树】P1047 校门外的树

    [题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...

  7. 【洛谷】【线段树】P1886 滑动窗口

    [题目描述:] 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. [输入格式:] 输入一共 ...

  8. 【洛谷】【线段树】P3353 在你窗外闪耀的星星

    [题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...

  9. 洛谷P5280 [ZJOI2019]线段树

      https://www.luogu.org/problemnew/show/P5280 省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不 ...

  10. 洛谷P3374(线段树)(询问区间和,支持单点修改)

    洛谷P3374 //询问区间和,支持单点修改 #include <cstdio> using namespace std; ; struct treetype { int l,r,sum; ...

随机推荐

  1. 获取view宽高

    在oncreate()中利用view.getWidth()或是view.getHeiht()来获取view的宽和高,看似没有问题,其实他们去得值是0,并不是你想要的结果? 这是为什么呢? 在调用onc ...

  2. [翻译]NUnit--前言(一)

    前言: 翻译这个系列主要是自己在学习NUnit之时看英文文档大部分能看懂但是有些还是功底不足,所以在方便自己以后再学习的时候可以快速查找,也能够加深印象以及掌握的更好.同时在搜索网上关于NUnit系列 ...

  3. [翻译]NUnit--Getting Started(二)

    Getting Started with NUnit 如果你打算开始学习,到下载页面选择一个NUnit版本.安装页面包含了安装说明. 开始NUnit阅读Quick Start页面.验证了一个C#银行应 ...

  4. Ural 1382 2SAT

    ural1382 直接套用 2SAT模板 缩点 拓扑排序... #include<iostream> #include<cstdio> #include<cstdlib& ...

  5. uva1560

    In an extended version of the game Lights Out®, is a puzzle with 5 rows of 6 buttons each (the actua ...

  6. ECS服务器配置密钥登录及常用日志

    一.介绍 1.SSH(22端口)是Secure Shell Protocol的简写,由IETF网络工作小组(Network Working Group)制定:在进行数据传输之前,SSH先对联机数据包通 ...

  7. 0623-TP框架整理一(下载、入口文件、路由、创建控制器、调用模板、系统常量、命名空间)

    一.下载解压后用ThinkPHP(核心)文件 核心文件夹(ThinkPHP)不要改,是作用于全局的,有需要可以改应用目录(Application) 二.创建入口文件: 运行后出现欢迎界面,在说明系统自 ...

  8. bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+树形dp】

    二分答案,然后dp判断是否合法 具体方法是设f[u]为u点到其子树中的最长链,每次把所有儿子的f值取出来排序,如果某两条能组合出大于mid的链就断掉f较大的一条 a是全局数组!!所以要先dfs完子树才 ...

  9. array_column() 函数[二维数组转为一维数组]

    array_column() 函数 输出数组中某个键值的集合[二维数组转为一位数组] <?php // 表示由数据库返回的可能记录集的数组 $a = array( array( 'id' =&g ...

  10. 【Linux】小米路由开启SSH访问权限

    一.验证小米路由ROM是否为开发版 1.  登录小米路由Web管理页面,检查ROM版本是否为开发版(若为开发版直接跳至第二步,若为稳定版继续本步骤). 2. 进入小米路由器官网(http://www1 ...