题意:一个多重集合的价值为将其变为公差为ddd(将在第一行输入)的等差数列需要插入几个数字(无法实现价值为0)。多次询问l,rl,rl,r,求[l,r][l,r][l,r]的子区间的价值和。
序列长度3e53e53e5,数字大小和d≤1e7d\leq 1e7d≤1e7

首先对于r′>rr'>rr′>r,lll使得[l,r][l,r][l,r]是最长的可以实现的区间,l′l'l′是使得[l′,r′][l',r'][l′,r′]是最长的可以实现的区间,那么l′≥ll' \geq ll′≥l,所以我们可以用双指针扫一遍求出所有可以实现的区间在哪些区间内。
那么对于所有可以实现的区间,我们有一个简单的方法可以计算一个区间[l,r][l,r][l,r]构成的集合的价值:
最大值d−最小值d+l−r\frac {最大值}d - \frac {最小值}d + l - rd最大值​−d最小值​+l−r
然后就是很套路的在双指针的同时维护两个单调栈,在栈中发生插入和删除操作的同时在线段树上区间加减。
那么如果我们问的是[l,r][l,r][l,r]的价值,离线后就是双指针右端点到达rrr时,单点查询lll.
如果问的是∑i=lr[i,r]\sum_{i=l}^r [i,r]∑i=lr​[i,r]的价值,那么就是区间查询l,rl,rl,r
可是我们询问的是∑i=lr∑j=ir[i,j]\sum_{i=l}^r \sum_{j=i}^r [i,j]∑i=lr​∑j=ir​[i,j]的价值和。
这就意味着我们在右端点是rrr的时候还需要统计到右端点是r−1...r-1...r−1...的答案。
所以我们假设右端点在iii的时候就是我们线段树的第iii个版本。
那么我们相当于就是要求线段树的历史版本区间和hsumhsumhsum。
需要增加一个标记tagtagtag,这个标记的意义是:
当一个区间打上tag+=vtag += vtag+=v时,hsum+=sum∗vhsum += sum * vhsum+=sum∗v。然后在之后下放给儿子。
考虑这个标记会和区间加addaddadd标记有不良互动。于是我们让一个区间在同时有addaddadd和tagtagtag时先下放addaddadd再下放tagtagtag。
那么在一个有addaddadd的点上打tagtagtag不会影响先后顺序,没有问题。但是反过来在有tagtagtag的点上打addaddadd后下放这个点的标记就会造成前后颠倒。
那么就把多加的hsumhsumhsum减回去,新加一个标记addhaddhaddh,当一个区间打上addh+=vaddh+= vaddh+=v时,hsum+=len∗vhsum += len * vhsum+=len∗v。然后在之后下放给儿子,这里的len是这个区间的长度。
那么就结束了。

ACCode\rm AC \ CodeAC Code

#include<bits/stdc++.h>
#define maxn 300005
#define F first
#define S second
#define mp make_pair
#define pii pair<int,int>
#define LL long long
#define lc u<<1
#define rc lc|1
using namespace std;int n,d,Q,S[maxn];
vector<pii >G[maxn];LL sm[maxn<<3],hsm[maxn<<3],ad[maxn<<3],adh[maxn<<3],len[maxn<<3],had[maxn<<3];
void dtp2(int u,int v){ had[u] += v , hsm[u] += sm[u] * v; }
void dtp3(int u,LL v,int t=1){ adh[u] += v; if(t) hsm[u] += v * len[u]; }
void dtp1(int u,int v){ if(had[u]) dtp3(u,-1ll*had[u]*v,0);ad[u] += v , sm[u] += 1ll * len[u] * v;
}
void dt(int u){ if(ad[u]) dtp1(lc,ad[u]),dtp1(rc,ad[u]),ad[u]=0; if(adh[u]) dtp3(lc,adh[u]),dtp3(rc,adh[u]),adh[u]=0;if(had[u]) dtp2(lc,had[u]),dtp2(rc,had[u]),had[u]=0;
}
void add(int u,int l,int r,int ql,int qr,int v){if(l>qr||ql>r) return;if(ql<=l&&r<=qr) return (void)(dtp1(u,v));int m=l+r>>1;dt(u);add(lc,l,m,ql,qr,v),add(rc,m+1,r,ql,qr,v);sm[u] = sm[lc] + sm[rc];
}
void pud(int u,int l,int r,int ql,int qr){if(l>qr||ql>r) return;if(ql<=l&&r<=qr) return (void)(dtp2(u,1));int m=l+r>>1;dt(u);pud(lc,l,m,ql,qr),pud(rc,m+1,r,ql,qr);hsm[u] = hsm[lc] + hsm[rc];
}
LL qry(int u,int l,int r,int ql,int qr){if(l>qr||ql>r) return 0;if(ql<=l&&r<=qr) return hsm[u];int m=l+r>>1;dt(u);return qry(lc,l,m,ql,qr) + qry(rc,m+1,r,ql,qr);
}
void Build(int u,int l,int r){if(l>r) return;len[u] = r-l+1;if(l==r) return;int m=l+r>>1;Build(lc,l,m),Build(rc,m+1,r);
}
int st[2][maxn],qr[2];
int cd[10000007],scd,usd[10000007],sud;
LL ans[maxn];int main(){freopen("arithmetic.in","r",stdin);freopen("arithmetic.out","w",stdout);scanf("%d%d%d",&n,&d,&Q);for(int i=1;i<=n;i++) scanf("%d",&S[i]);for(int i=1,a,b;i<=Q;i++){scanf("%d%d",&a,&b);G[b].push_back(mp(a,i));}Build(1,1,n);for(int i=1,j=1;i<=n;i++){for(;qr[0] && S[st[0][qr[0]]] >= S[i];qr[0]--)add(1,1,n,st[0][qr[0]-1]+1,st[0][qr[0]],(S[st[0][qr[0]]]/d));st[0][++qr[0]] = i;add(1,1,n,st[0][qr[0]-1]+1,i,-(S[i]/d));for(;qr[1] && S[st[1][qr[1]]] <= S[i];qr[1]--)add(1,1,n,st[1][qr[1]-1]+1,st[1][qr[1]],-(S[st[1][qr[1]]]/d));st[1][++qr[1]] = i;add(1,1,n,st[1][qr[1]-1]+1,i,S[i]/d);if(i>1) add(1,1,n,1,i-1,-1);scd += (cd[S[i] % d] ++ == 0);sud += (++usd[S[i]] == 2);for(;j<=n && (scd > 1 || sud >= 1);j++)scd -= (--cd[S[j] % d]  == 0),sud -= (usd[S[j]]-- == 2);pud(1,1,n,j,i);for(int k=0;k<G[i].size();k++)ans[G[i][k].S] = qry(1,1,n,G[i][k].F,i);} for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
}

Arithmetic(线段树维护历史版本和)相关推荐

  1. 【uoj#164】[清华集训2015]V 线段树维护历史最值

    题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ : $2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ , ...

  2. BZOJ #3064. Tyvj 1518 CPU监控(线段树,历史最值)

    BZOJ #3064. Tyvj 1518 CPU监控(线段树,历史最值) Solution 我们考虑用线段树维护此题. 先不考虑历史最值. 大概需要维护一种特殊的懒标记(x,y)(x,y)(x,y) ...

  3. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  4. 【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNav=acm 来源:牛客网 Given a maze with N rows an ...

  5. [动态dp]线段树维护转移矩阵

    背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区 ...

  6. Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)

    题意: 操作1:把x位置的数字修改成y. 操作2:查询[l,r]之间不下降序列的个数. 题解: 线段树维护区间和问题 (这是套路,想不到只能说做题少别打我) . 用五个变量进行维护. sum区间总个数 ...

  7. [SDOI2011]染色 (线段树维护子段问题+树剖)

    题意: 给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种: 1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c. 2.询问节点 a 到节点 b 的路径上的颜色段 ...

  8. Can you answer these queries III (线段树维护最大子段和)

    题意: 求一个区间的最大连续和. 0:表示把A[x]改成y 1:表示求[x,y]这个区间的最大连续和. 题解: 线段树维护四个变量. 倒着讲,先来看如何维护这四个变量. summax代表这个区间连续最 ...

  9. 线段树 ---- D. Power Tree(离线dfs序+线段树维护树上多条路径和的技巧)

    题目链接 题目大意: 一开始给你只有一个点111的树,有qqq次询问.每次询问有两种操作 1pv1\;p\;v1pv 就是把最小的没加入的点,加入这个树,它的父亲是ppp,权值是vvv 2u2\;u2 ...

最新文章

  1. 深度学习中的注意力机制(一)
  2. 用bitmap实现中位数的算法
  3. java中tomcat检测_eclipse+tomcat测试JSP
  4. java代码删除文件夹_删除文件夹的java类
  5. win10你的电脑设备需要修复_图文详解win10升级失败的解决方法
  6. 北大计算机基础与应用,北大16秋《计算机基础与应用-第六组》在线作业
  7. You are here: Prof Andrew Binley's Homepage R3t
  8. Java的GUI学习九(列出指定目录内容)
  9. Duilib中Webbrowser事件完善使其支持判断页面加载完毕
  10. java强制删文件夹_Java 删除文件夹 和 文件 集合
  11. 市场竞争力法则:以小博大,虽败犹荣
  12. 电子计算机按用途分类包括,计算机的分类试题解析
  13. angular 万年历_jQuery实现的简单日历组件定义与用法示例
  14. 存储过程(Stored Procedure)
  15. java画笑脸_canvas 画笑脸
  16. 高通平台ITS:scene2_a/test_effects fail
  17. java byreference_深入理解Java中的引用(一)——Reference
  18. java获取当前时间的小时
  19. 常用 IT 论坛及专业技术网站
  20. 【ACMMM 2022】Learning Hierarchical Dynamics with Spatial Adjacency for Image Enhancement

热门文章

  1. [NepCTF]WEB
  2. 这些信贷数据埋点中不得不知的埋点知识
  3. vuepress-theme-reco评论管理
  4. ps怎么将图片制作成ico图标? ps制作ico图标的教程
  5. 在Ubuntu安装Deepin软件
  6. 《机器学习基石》学习笔记 1 The Learning Problem
  7. 基于html5的五子棋游戏
  8. 如何解决外边距重叠问题
  9. 阿里和微博的异地多活方案
  10. win 7硬盘安装centos7 亲测可行