题目详情:https://www.luogu.org/problemnew/show/P3373

这个线段树模板写的头疼(最后纠错发现一个long long没开差点一口血喷出来),思路就是在普通的求区间和线段树中使用两个update函数,一个负责加法,一个负责乘法(同理在线段树的结构体里自然也有addmark和mulmark)。这里我们将延迟标记乘的优先级设置高于延迟标记加,原因是当我需要给一段区间乘一个数,他并不不会因为之后这段区间上加了某一个数而使这个标记改变,但是我先加一个数后再乘一个数,根据mulmark的值,addmark就会有改变,具体看例子。

一个长度为5的数列

1 2 3 4 5

第一次我将它在区间[1,3]上乘以2,他在这段区间上的和直接先乘以2,[1,3]上的延迟标记乘变为2,而我再在区间[1,3]上加2,他除了在这段区间上的和加上了(3-1+1)*2,延迟标记加也变为2,然后我查询[1,2]的和,延迟标记往下传递,他的和就等于(2-1+1)*2+3*2=10(即延迟标记加乘以区间长度加上原值乘以延迟标记乘)。那我们将这个操作反过来,先在区间[1,3]上加2,再乘2,那么首先延迟标记加就会变成2,而在乘2的时候,除了延迟标记乘会变成2,延迟标记加也会变成2*2(延迟标记加*延迟标记乘),所以和为(2-1+1)*4+3*2=14。这是因为之后乘的那个数使之前的增加量也乘了相应的量,所以这样处理。

#include<stdio.h>
#include<stdlib.h>
long long a[5000001]={0};
int n,m,p;
struct seg{long long val;long long mulmark;long long addmark;
}seg[5000000];
int build(int root,int istart,int iend)
{int mid;seg[root].addmark=0;seg[root].mulmark=1;if(istart==iend){seg[root].val=a[istart];}else{mid=(istart+iend)/2;build(root*2,istart,mid);build(root*2+1,mid+1,iend);seg[root].val=seg[root*2].val+seg[root*2+1].val;}seg[root].val=seg[root].val%=p;return 0;
}
long long quire(int root,int nstart,int nend,int qstart,int qend)
{int mid;if(nstart>qend||qstart>nend)return 0;if(qstart<=nstart&&qend>=nend)return seg[root].val;push(root,nstart,nend);mid=(nstart+nend)/2;return (quire(root*2,nstart,mid,qstart,qend)+quire(root*2+1,mid+1,nend,qstart,qend))%p;
}
int push(int root,int nstart,int nend)
{int mid;long long t1,t2;mid=(nstart+nend)/2;t1=seg[root].addmark;t2=seg[root].mulmark;seg[root*2].val=(seg[root*2].val*t2+t1*(mid-nstart+1))%p;seg[root*2+1].val=(seg[root*2+1].val*t2+t1*(nend-mid))%p;seg[root*2].addmark=(seg[root*2].addmark*t2+t1)%p;seg[root*2+1].addmark=(seg[root*2+1].addmark*t2+t1)%p;seg[root*2].mulmark*=t2;seg[root*2].mulmark%=p;seg[root*2+1].mulmark*=t2;seg[root*2+1].mulmark%=p;seg[root].addmark=0;seg[root].mulmark=1;return 0;
}
int updateadd(int root,int nstart,int nend,int ustart,int uend,long long add)
{int mid;if(ustart>nend||nstart>uend)return 0;if(ustart<=nstart&&uend>=nend){seg[root].val+=(nend-nstart+1)*add;seg[root].val%=p;seg[root].addmark+=add;seg[root].addmark%=p;return 0;}push(root,nstart,nend);mid=(nstart+nend)/2;updateadd(root*2,nstart,mid,ustart,uend,add);updateadd(root*2+1,mid+1,nend,ustart,uend,add);seg[root].val=(seg[root*2].val+seg[root*2+1].val)%p;return 0;
}
int updatemul(int root,int nstart,int nend,int ustart,int uend,long long mul)
{int mid;if(ustart>nend||nstart>uend)return 0;if(ustart<=nstart&&uend>=nend){seg[root].val*=mul;seg[root].val%=p;seg[root].mulmark*=mul;seg[root].mulmark%=p;seg[root].addmark*=mul;seg[root].addmark%=p;return 0;}push(root,nstart,nend);mid=(nstart+nend)/2;updatemul(root*2,nstart,mid,ustart,uend,mul);updatemul(root*2+1,mid+1,nend,ustart,uend,mul);seg[root].val=(seg[root*2].val+seg[root*2+1].val)%p;return 0;
}
int main()
{int i,flag,x,y;long long k;scanf("%d%d%d",&n,&m,&p);for(i=1;i<=n;i++)scanf("%lld",&a[i]);build(1,1,n);for(i=1;i<=m;i++){scanf("%d",&flag);if(flag==1){scanf("%d%d%lld",&x,&y,&k);updatemul(1,1,n,x,y,k);}else if(flag==2){scanf("%d%d%lld",&x,&y,&k);updateadd(1,1,n,x,y,k);}else if(flag==3){scanf("%d%d",&x,&y);printf("%lld\n",quire(1,1,n,x,y));}}return 0;
}

洛谷3373 线段树模板相关推荐

  1. 洛谷 3373 线段树

    传送门 思路: 关键在于乘与加的先后计算关系,(x + y) * k = x * k + y * k,从这里可以看出来,把加法转化为乘法计算,取消了+与*先后顺序 pushdown时,即为乘法标记 * ...

  2. 洛谷 P3373 线段树模板题

    链接:https://www.luogu.com.cn/problem/P3373 题意:一个区间 三种操作 1 给lr范围内乘一个数 2 给lr范围内加一个数 3 询问lr范围内的和 啊这题真·做了 ...

  3. 洛谷P3373线段树

    洛谷P3373 线段树模板题,主要对懒标的处理要求比较高. 有三种操作: 区间加法 区间乘法 区间求和查询 tips:我们对一个区间进行乘k操作的时候,他之前可能存在加法lazy还没pushdown, ...

  4. 洛谷 P3373 线段树2

    洛谷 P3373 线段树2 mul和pls更新某区间左右子树sum的时候,别忘了回头更新这个区间的sum 只有在传递给子序列之后,父序列的lz标记才能清零.其他时候,lz标记只增不减 #include ...

  5. 洛谷P3373线段树2

    题目描述 区间查询区间修改,非常明显的线段树模板,但乘法和加法的结合,使问题有了些小改动: problem: 该题唯一的难点就是加法和乘法的lazytag的处理,设目前区间N.s(即区间和)=x,若先 ...

  6. 洛谷P3373 线段树2(乘法加法lazytag)

    线段树模板题,含lazytag的线段树码量本身就比较大,再加入乘法标记,还要考虑先乘后加的问题,本蒟蒻一调就是几个小时. P3373 [模板]线段树 2https://www.luogu.com.cn ...

  7. [WC2005]双面棋盘,洛谷P4121,线段树分治+可撤销并查集

    正题 这题主要是来练手的,因为没写过可撤销的并查集,大概就是把每一个格子看成一个点,然后格子直接的边有很多的出现区间,把这些出现区间和对应的颜色打到线段树上,然后用可撤销的并查集来维护就可以了. #i ...

  8. hdu1156(简单线段树 模板题)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  9. 线段树模板hdu 1754:I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

最新文章

  1. Ubuntu Linux经典著作
  2. php新闻模块,新闻模块实现
  3. mac系统及xcode使用的SVN客户端安装升级
  4. Linux——VIM学习选取多行(转)
  5. linux配置iscsi无账号密码,linux4 如何配置iscsi启动器
  6. udp 协议阻断_应对UDP反射放大攻击的五种常用防护思路
  7. 计算机科学的鼻祖,现代计算机科学的鼻祖,编程界的上帝
  8. js实现点击“验证码”开始倒计时
  9. slopShell:强大的PHP Webshell
  10. ISO50001认证辅导,ISO50001能源管理体系的框架审核通过系统的提高能源效率和消耗
  11. VS2015社区版MFC安装
  12. 怎么教你如何查看电脑的蓝牙版本【解决方案】
  13. 微信开放平台和公众平台的区别
  14. 高中计算机应用基础知识课件,计算机应用基础(windows 7+office 2010)课件 第一章 计算机基础知识.ppt.pdf-汇文网...
  15. Brave vs Google Chrome:哪个浏览器更适合你?
  16. 利用 API 爬取数据,试着爬取 QQ 音乐流行指数榜
  17. 数商云:打通产销对接,构建新型数字化农副产品供应链
  18. 4年程序员30天面试了23家公司,看到公司名单后,网友:羡慕
  19. 鲲鹏生态“开花结果”,这一次是鹏城云脑Ⅱ
  20. 计算机xp系统恢复以前设置,最新版:如何在XP系统计算机上恢复出厂设置?

热门文章

  1. 开源共轴双桨无人机 Tdrone 软硬件全部在 GitHub 开源
  2. LibJpeg的安装与修复颜色错误图像错位保姆级教程
  3. prop与自定义事件
  4. 剑指offer算法题分析与整理(二)
  5. 软件开发生命周期及开发模型
  6. 数据中台:建立在数据网络效应之上的赛道
  7. 登陆共享服务器的用户名和密码怎么修改
  8. 启动Tomcat6.x时manager does not exist or is not a readable directory
  9. 如何伪装成一个服务端开发(五)
  10. Git 使用 stash暂存代码