HDU4578 Transformation (多操作线段树)
终于过了这道题。。
要注意标记之间的影响,和add操作时更新求和的顺序。
same 区间每个数设置为x标记
mult 区间每个数乘x标记
add 区间每个数加x标记
①:当打same标记时,mult标记和add标记就没用了,要初始化。
②:当打mult标记时,add标记也要乘相应的值。
---------------求和可以递推过来---------------
1次方求和就正常求和
即:sum1[rt]=sum1[rt]+(r-l+1)*val;
2次方 可以由 (x+val)2 = x2+val2+2*x*val
即:sum2[rt]=sum2[rt]+2*sum1[rt]*val+(r-l+1)*val*val;
3次方 可以由 (x+val)3 = x3+val3+3*x2*val+3*x*val2
即:sum3[rt]=sum3[rt]+(r-l+1)*val*val*val+3*sum2[rt]*val+3*sum1[rt]*val*val;
再次注意 add求和要按照sum3,sum2, sum1的顺序!
算是又对取模有了一点了解。。
a*b*c*d 取模为 (a*b%mod) * (c*d%mod) %mod
a+b*c*d+3*a*b*c*d 取模为 (a + (b*c)%mod*d + 3*((a*b)%mod)*((c*d)%mod)%mod)%mod
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long ll;
- const int mod=;
- const int maxx=;
- ll add[maxx<<],mult[maxx<<],same[maxx<<];
- ll sum1[maxx<<],sum2[maxx<<],sum3[maxx<<];
- int n,m,sum;
- void pushup(int rt) {
- sum1[rt]=(sum1[rt<<]+sum1[rt<<|])%mod;
- sum2[rt]=(sum2[rt<<]+sum2[rt<<|])%mod;
- sum3[rt]=(sum3[rt<<]+sum3[rt<<|])%mod;
- }
- void build(int l,int r,int rt) {
- add[rt]=same[rt]=;
- mult[rt]=;
- if(l==r) {
- sum1[rt]=sum2[rt]=sum3[rt]=;
- return;
- }
- int mid=(l+r)>>;
- build(l,mid,rt<<);
- build(mid+,r,rt<<|);
- pushup(rt);
- }
- void pushdown(int rt,int len) { //下传标记
- if(same[rt]) {
- sum1[rt<<]=(len-(len>>))*same[rt]%mod;
- sum1[rt<<|]=(len>>)*same[rt]%mod;
- sum2[rt<<]=((len-(len>>))*same[rt]%mod)*same[rt]%mod;
- sum2[rt<<|]=((len>>)*same[rt]%mod)*same[rt]%mod;
- sum3[rt<<]=((len-(len>>))*same[rt]%mod)*(same[rt]*same[rt]%mod)%mod;
- sum3[rt<<|]=((len>>)*same[rt]%mod)*(same[rt]*same[rt]%mod)%mod;
- same[rt<<]=same[rt<<|]=same[rt];
- add[rt<<]=add[rt<<|]=; //也需要改变
- mult[rt<<]=mult[rt<<|]=; //也需要改变
- same[rt]=;
- }
- if(mult[rt]!=) {
- mult[rt<<]=mult[rt<<]*mult[rt]%mod;
- mult[rt<<|]=mult[rt<<|]*mult[rt]%mod;
- add[rt<<]=add[rt<<]*mult[rt]%mod; //改变
- add[rt<<|]=add[rt<<|]*mult[rt]%mod; //改变
- sum1[rt<<]=sum1[rt<<]*mult[rt]%mod;
- sum1[rt<<|]=sum1[rt<<|]*mult[rt]%mod;
- sum2[rt<<]=(sum2[rt<<]*mult[rt]%mod)*mult[rt]%mod;
- sum2[rt<<|]=(sum2[rt<<|]*mult[rt]%mod)*mult[rt]%mod;
- sum3[rt<<]=(sum3[rt<<]*mult[rt]%mod)*(mult[rt]*mult[rt]%mod)%mod;
- sum3[rt<<|]=(sum3[rt<<|]*mult[rt]%mod)*(mult[rt]*mult[rt]%mod)%mod;
- mult[rt]=;
- }
- if(add[rt]) {
- add[rt<<]=(add[rt<<]+add[rt])%mod;
- add[rt<<|]=(add[rt<<|]+add[rt])%mod;
- sum3[rt<<]=(sum3[rt<<]+*sum2[rt<<]*add[rt]%mod+*(sum1[rt<<]*add[rt]%mod)*add[rt]%mod+(add[rt]*add[rt]%mod)*(add[rt]*(len-(len>>))%mod))%mod;
- sum3[rt<<|]=(sum3[rt<<|]+*sum2[rt<<|]*add[rt]%mod+*(sum1[rt<<|]*add[rt]%mod)*add[rt]%mod+(add[rt]*add[rt]%mod)*(add[rt]*(len>>)%mod))%mod;
- sum2[rt<<]=(sum2[rt<<]+*sum1[rt<<]*add[rt]%mod+(add[rt]*add[rt]%mod)*(len-(len>>))%mod)%mod;
- sum2[rt<<|]=(sum2[rt<<|]+*sum1[rt<<|]*add[rt]%mod+(add[rt]*add[rt]%mod)*(len>>)%mod)%mod;
- sum1[rt<<]=(sum1[rt<<]+(len-(len>>))*add[rt]%mod)%mod;
- sum1[rt<<|]=(sum1[rt<<|]+(len>>)*add[rt]%mod)%mod;
- add[rt]=;
- }
- }
- void updata(int L,int R, int val,int op,int l,int r,int rt) {
- if(L<=l&&R>=r) {
- if(op==) {
- same[rt]=val;
- mult[rt]=; //改变
- add[rt]=; //改变
- sum1[rt]=(r-l+)*val%mod;
- sum2[rt]=((r-l+)*val%mod)*val%mod;
- sum3[rt]=((r-l+)*val%mod)*(val*val%mod)%mod;
- } else if(op==) {
- mult[rt]=mult[rt]*val%mod;
- add[rt]=add[rt]*val%mod; //改变
- sum1[rt]=sum1[rt]*val%mod;
- sum2[rt]=(sum2[rt]*val%mod)*val%mod;
- sum3[rt]=(sum3[rt]*val%mod)*(val*val%mod)%mod;
- } else if(op==) {
- add[rt]=(add[rt]+val)%mod;
- sum3[rt]=(sum3[rt]+*sum2[rt]*val%mod+*(sum1[rt]*val%mod)*val%mod+(((r-l+)*val%mod)*(val*val%mod)%mod))%mod;
- sum2[rt]=(sum2[rt]+*sum1[rt]*val%mod+((r-l+)*val%mod)*val%mod)%mod;
- sum1[rt]=(sum1[rt]+(r-l+)*val%mod)%mod;
- }
- return;
- }
- pushdown(rt,r-l+);
- int mid=(l+r)>>;
- if(L<=mid) updata(L,R,val,op,l,mid,rt<<);
- if(R>mid) updata(L,R,val,op,mid+,r,rt<<|);
- pushup(rt);
- }
- ll query(int L,int R,int val,int l,int r,int rt) {
- if(L<=l&&R>=r) {
- if(val==) {
- return sum1[rt]%mod;
- } else if(val==) {
- return sum2[rt]%mod;
- } else return sum3[rt]%mod;
- }
- ll sum=;
- pushdown(rt,r-l+);
- int mid=(l+r)>>;
- if(L<=mid) sum=(sum+query(L,R,val,l,mid,rt<<))%mod;
- if(R>mid) sum=(sum+query(L,R,val,mid+,r,rt<<|))%mod;
- return sum;
- }
- int main() {
- while(~scanf("%d%d",&n,&m)) {
- if(n==&&m==) break;
- build(,n,);
- while(m--) {
- int op,x,y,val;
- scanf("%d%d%d%d",&op,&x,&y,&val);
- if(op==) {
- printf("%lld\n",query(x,y,val,,n,));
- }
- else updata(x,y,val,op,,n,);
- }
- }
- }
HDU4578 Transformation (多操作线段树)的更多相关文章
- COGS 2638. 数列操作ψ 线段树
传送门 : COGS 2638. 数列操作ψ 线段树 这道题让我们维护区间最大值,以及维护区间and,or一个数 我们考虑用线段树进行维护,这时候我们就要用到吉司机线段树啦 QAQ 由于发现若干次an ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- 【BZOJ2962】序列操作 线段树
[BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...
- Luogu P2572 [SCOI2010]序列操作 线段树。。
咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...
- BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs
题意 直接照搬原题面 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...
随机推荐
- linux centos 恢复 还原 备份 Snapper 快照说明
为什么要使用Snapper快照? 我们可以想像以下场景: 1. 场景一:系统发生意外宕机,工程师无法快速定位问题,业务受到中断,客户十分不满意. 2. 场景二:项目会议上,就是否升级某软件到最新版本, ...
- img属性src的特点
img属性src的特点: src=“图片地址” 成功则加载图片,失败则显示alt文字和断裂的图片 src="" 则不加载,不显示alt文字和断裂的图片 因此当图片加载失败后,$(& ...
- jvisualvm图解【转】
jvisualvm图解[转] http://blog.csdn.net/a19881029/article/details/8432368 jvisualvm能干什么:监控内存泄露,跟踪垃圾回收, ...
- 二.ES6新的声明方式
前言: 以前我们在声明时只有一种方法,就是使用var来进行声明,ES6对声明的进行了扩展,现在可以有三种声明方式了. 字面理解ES6的三种声明方式: var:它是variable的简写,可以理解成变量 ...
- Vim操作 -- 多段复位粘贴
Vim可以多段复制.粘贴.即,内容X复制到寄存器“1”,内容Y复制到寄存器“2”:粘贴时可以选择从“1”还是“2”粘贴. (1) Vim有13个粘贴板,分别是0.1.2.....9.a.“.+:用:r ...
- [JZOJ4639] 【NOIP2016提高组A组7.16】Angel Beats!
题目 描述 题目大意 给你一棵树,每次询问两个点,求出这两个点的子树的重心到其中每个点的距离和. 重心的定义是到其中每个点距离和最小的点(不一定在两棵子树内) 思考历程 想想以前我是怎么求重心的呢-- ...
- SQLite C++操作类
为了方便SQLite的使用,封装了一个SQLite的C++类,同时支持ANSI 和UNICODE编码.代码如下: 头文件(SQLite.h) [cpp] view plaincopy /***** ...
- 修改文本框和文本域placeholder样式
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { font-size:20px; padding:20px ...
- Jeecg-Boot前后端分离,针对敏感数据,加密传递方案
# 针对敏感数据,加密传递方案 第一步: 在vue页面引入aesEncrypt.js encryption方法.示例代码: import { encryption } from '@/utils/en ...
- C++写矩阵的转置
(2019年2月19日注:这篇文章原先发在自己github那边的博客,时间是2017年2月5日) 对于任意非n阶矩阵的转置,用c++应该怎么写代码,思考了一下,发现并没有那么简单,上网找到了一个比较好 ...