博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
luogu-P3373 【模板】线段树 2
阅读量:6554 次
发布时间:2019-06-24

本文共 3757 字,大约阅读时间需要 12 分钟。

题目描述

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

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

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

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

输入输出格式

输入格式:

 

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

 

输出格式:

 

输出包含若干行整数,即为所有操作3的结果。

 

输入输出样例

输入样例#1: 
5 5 381 5 4 2 32 1 4 13 2 51 2 4 22 3 5 53 1 4
输出样例#1: 
172

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^)

样例说明:

故输出应为17、2(40 mod 38=2)

 

好久没有写过博客了,快noip了,又上机房来做题目,不过这次上来是来做模板题的qwq

很久没有打过代码了,打起来生疏了不少呀。。。

我们来看看这道题目

这道题目要求我们区间乘法,区间加法和区间求和

我们首先来考虑加法和乘法怎么“兼容”

我们可以用两个lazytag,这里用mark[].mul表示乘,mark[].add表示加

我们可以默认乘法优先,

每次乘的时候,连mark[].add也一起乘,因为加法的lazytag可能还没有下放,如果只修改mark[].mul,我们默认的乘法优先就会出现错误

每次加的时候,只要修改mark[].add就可以了

pushdown的时候我们就

tree[v<<1]=(tree[v<<1]*mark[v].mul+(mid-l+1)*mark[v].add)%p

tree[v<<1|1]=(tree[v<<1|1]*mark[v].mul+(r-mid)*mark[v].add)%p

再维护一下lazytag就可以了

1 #include
2 #define N 100005 3 #define ll long long 4 using namespace std; 5 int n,m,p,s,x,y,k; 6 int a[N]; 7 ll tree[4*N]; 8 struct node{ 9 ll add,mul;10 }mark[4*N];11 void update(int v){12 tree[v]=(tree[v<<1]+tree[v<<1|1])%p;13 }14 void pushdown(int v,int l,int mid,int r){15 if (mark[v].mul!=1){16 (mark[v<<1].mul*=mark[v].mul)%=p;17 (mark[v<<1|1].mul*=mark[v].mul)%=p;18 (mark[v<<1].add*=mark[v].mul)%=p;19 (mark[v<<1|1].add*=mark[v].mul)%=p;20 (tree[v<<1]*=mark[v].mul)%=p;21 (tree[v<<1|1]*=mark[v].mul)%=p;22 mark[v].mul=1;23 }24 if (mark[v].add){25 (mark[v<<1].add+=mark[v].add)%=p;26 (mark[v<<1|1].add+=mark[v].add)%=p;27 (tree[v<<1]+=mark[v].add*(mid-l+1))%=p;28 (tree[v<<1|1]+=mark[v].add*(r-mid))%=p;29 mark[v].add=0;30 }31 }32 void build(int v,int l,int r){33 mark[v].mul=1;34 mark[v].add=0;35 if (l==r){36 tree[v]=a[l];37 return;38 }39 int mid=(l+r)>>1;40 build(v<<1,l,mid);41 build(v<<1|1,mid+1,r);42 update(v);43 }44 void mul(int v,int l,int r,int x,int y,int k){45 if (x<=l&&y>=r){46 (mark[v].mul*=k)%=p;47 (mark[v].add*=k)%=p;48 (tree[v]*=k)%=p;49 return;50 }51 int mid=(l+r)>>1;52 pushdown(v,l,mid,r);53 if (y<=mid) mul(v<<1,l,mid,x,y,k); else54 if (x>mid) mul(v<<1|1,mid+1,r,x,y,k); else55 mul(v<<1,l,mid,x,mid,k),mul(v<<1|1,mid+1,r,mid+1,y,k);56 update(v);57 }58 void add(int v,int l,int r,int x,int y,int k){59 if (x<=l&&y>=r){60 (mark[v].add+=k)%=p;61 (tree[v]+=(ll)(r-l+1)*k)%=p;62 return;63 }64 int mid=(l+r)>>1;65 pushdown(v,l,mid,r);66 if (y<=mid) add(v<<1,l,mid,x,y,k); else67 if (x>mid) add(v<<1|1,mid+1,r,x,y,k); else68 add(v<<1,l,mid,x,mid,k),add(v<<1|1,mid+1,r,mid+1,y,k);69 update(v);70 }71 ll query(int v,int l,int r,int x,int y){72 if (x<=l&&y>=r) return tree[v];73 int mid=(l+r)>>1;74 pushdown(v,l,mid,r);75 if (y<=mid) return query(v<<1,l,mid,x,y); else76 if (x>mid) return query(v<<1|1,mid+1,r,x,y); else77 return (query(v<<1,l,mid,x,mid)+query(v<<1|1,mid+1,r,mid+1,y))%p;78 }79 int main(){80 scanf("%d%d%d",&n,&m,&p);81 for (int i=1;i<=n;i++)82 scanf("%d",&a[i]),a[i]%=p;83 build(1,1,n);84 for (int i=1;i<=m;i++){85 scanf("%d%d%d",&s,&x,&y);86 if (s==1){87 scanf("%d",&k);88 mul(1,1,n,x,y,k);89 } else90 if (s==2){91 scanf("%d",&k);92 add(1,1,n,x,y,k);93 } else94 printf("%lld\n",query(1,1,n,x,y));95 }96 return 0;97 }
View Code

 

转载于:https://www.cnblogs.com/zhuchenrui/p/9637263.html

你可能感兴趣的文章
PHP 提交checkbox表单时 判断复选框是否被选中
查看>>
day12-sqlalchemy 常用语法
查看>>
Interval GCD CH4302
查看>>
Vim + SpaceVim强大的Linux系统下的编辑器
查看>>
dxRibbonRadialMenu控件使用
查看>>
知识总结:测试用例
查看>>
Xutils请求服务器json数据与下载文件
查看>>
2018 Wannafly summer camp Day2--Utawarerumono
查看>>
Spring系列之二——Spring初体验
查看>>
YII框架中的自动加载自定义数据模型操作
查看>>
什么是多态
查看>>
Adobe Flash Player 11.2 on Fedora 17/16, CentOS/RHEL 6.3/5.8
查看>>
使用ViewFlipper实现图片轮播
查看>>
C# 装箱和拆箱
查看>>
Vuex的基本使用
查看>>
关于Breeze.js+Angular.js+KendoUI+BootStrap+TypeScript+EF4.5的使用心得记录之一
查看>>
Java部署_IntelliJ创建一个可运行的jar包(实践)
查看>>
单元测试应具有的特点
查看>>
C# 类中索引器的使用
查看>>
iOS开发之苹果开发者账号注册申请流程
查看>>