[HNOI2016] 序列(线段树 + 莫队 + 倍增)

problem

luogu-P3246

心路历程+卡常历程+问题存疑

一直在想莫队的做法。发现左右指针的移动对应一段左/右端点固定的子序列,然后可以一个数代表一段相同的贡献。

就开始求 lsti,nxtilst_i,nxt_ilsti,nxti 了。

仔细想想需要找到 lstlsti<l≤lstilst_{lst_i}<l\le lst_ilstlsti<llsti 的特殊位置,然后要知道这中间点的贡献。

我就在来了个线段树维护区间和,然后用 set\text{set}setlstilst_ilsti 二分找。

后来半天过不了样例,不是过大就是过小。

隐约间觉得不对劲,后来真的好像不对劲,我就大刀阔斧直接砍了。

开始怀疑自己的莫队算法。此时经过了八点半到九点十分共四十多分钟的时间。

我开始尝试整体二分,后面发现自己完全不会分治。此时我陷入了困境。

我又倒回去想了下莫队,我发现问题出在 lstilst_ilsti 中间不是所有点都是对应在 [l,r][l,r][l,r] 的贡献,我好像算多了。

因为 lstilst_ilsti 是从 iii 出发得到的,而非整体的 rrr

难道我只用维护一个全局的?不,这样会算少。

突然我意识到可以把这种关系建成树!并且发现了编号之间与子序列间的对应关系。

此时时间大概在酒店四五十左右,我就开始敲了。

过程比较顺利,十点半不到?就敲完了。然后开始调,输出中间结果,发现最后结果已经和样例快要吻合时,我就更加坚定了自己的做法。

十一点我通过了小样例,紧接着大样例也是正确的。

但很遗憾,耗时 3.6s3.6s3.6s 多。

我发现输入数据过多,就换成了快读快输。耗时变成了 3.0s3.0s3.0s 多。

接着我觉得倍增对于极限数据也只会到 161616 ,所以卡了下倍增的循环。耗时缩减为 2.6s2.6s2.6s

改下块长加 O2O2O2 就能看看卡过。

但是当时我尝试了一下用莫队的奇偶优化,时间瞬间到了 1.9s1.9s1.9s 左右。

此时出现了个大问题!我发现这样就跑不过大样例了。

我对此非常疑惑。

下午又研究了一番,发现当我将莫队的四个指针移动前后两个交换位置,也会跑不过大样例?!!莫队询问排序块内按右端点降序排列也不行!

这下真给我整不会了,我突然猜是不是爆 long long 了,用 assert\text{assert}assert 发现没有,自己算极限也是 6e186e186e18 不到。

后面通过数据,我觉得应该是倍增到最后不能往上跳部分出现了问题。

但是这样怎么可能会让我的第一次建构代码跑过去呢?

至今我仍然不清楚。

只能说非常幸运的在第一次敲代码的时候就跑过去了把。

如果有人知道这是为什么的话,麻烦请联系一下我!谢谢了。

solution

由于昨天做的一道题题解提了一句莫队二次离线,形式就是 l≤x≤y≤rl\le x\le y\le rlxyr

所以一看到这个题,我就在想莫队的做法。

莫队反正就是左端点分块排序,右端点块内递增,就两个指针移动的板子,时间复杂度就带了个 n\sqrt{n}n

问题是如何快速计算移动 l/rl/rl/r 一个位置后对应的答案动态变化。

以右移 rrr 为例,当 r←r+1r\leftarrow r+1rr+1的时候,我们需要新加 [l,r]∼r+1[l,r]\sim r+1[l,r]r+1r−l+1r-l+1rl+1 组新的子序列贡献。

然后发现,我们只需要跳较小值的位置即可。

具体而言,假设 ppp 满足 ap≤ar+1∧∀p<i<r+1ai>ar+1a_p\le a_{r+1}\wedge \forall_{p<i<r+1}\ a_i>a_{r+1}apar+1p<i<r+1 ai>ar+1

最大的不超过 ar+1a_{r+1}ar+1 的位置,记为 lstr+1lst_{r+1}lstr+1

则对于 [p,r]∼r+1[p,r]\sim r+1[p,r]r+1r−p+1r-p+1rp+1 组子序列的贡献都是 apa_pap

同理我们找到 lstplst_plstp,然后共 p−lstp+1p-lst_p+1plstp+1 组子序列的贡献都是 alstpa_{lst_p}alstp

以此类推…\dots直到跳到 <l<l<l 的位置,lll 开头那一段贡献可能不完整,简单处理一下即可。

我们肯定不能暴力跳,注意到一个数对应的完整区间贡献是固定的,所以我们可以倍增!

我们将 lsti→ilst_i\rightarrow ilstii 建立有向边,然后生成一棵树,不难发现。(u−fa)∗au(u-fa)*a_u(ufa)au 即为 uuu 对应的完整贡献。

在这里插入图片描述

至于找 lstilst_ilsti,答主比较无脑,直接权值线段树上,完全不带脑子的大常数。而且 aia_iai 值域过大,还加了个离散化。

rrr 左移减去贡献与上面的过程完全一样。

lll 的左移右移则需要维护 nxtinxt_inxti,最小的不大于 aia_iai 的位置。获得方式同 lstilst_ilsti

同样 nxti→inxt_i\rightarrow inxtii 建立有向边,生成一棵树。

在这里插入图片描述

为了使得点与父节点之间能算出点的贡献,我们钦定找不到的 lsti=0,nxti=n+1lst_i=0,nxt_i=n+1lsti=0,nxti=n+1

时间复杂度大概是 O(nnlog⁡n)O(n\sqrt n\log n)O(nnlogn)

会被卡,那就稍微调整一下块长。

code

#include <bits/stdc++.h>
using namespace std;
#define lson now << 1
#define rson now << 1 | 1
#define mid  (l + r >> 1)
#define ll long long
#define maxn 100005
int n, Q, B; ll ans;
int a[maxn], b[maxn], block[maxn], lst[maxn], nxt[maxn];
ll ret[maxn];
struct query { int l, r, id; }q[maxn];namespace MaxSgt {int Max[maxn << 2];void modify( int now, int l, int r, int p, int v ) {if( l == r ) { Max[now] = v; return; }if( p <= mid ) modify( lson, l, mid, p, v );else modify( rson, mid + 1, r, p, v );Max[now] = max( Max[lson], Max[rson] );}int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return 0;if( L <= l and r <= R ) return Max[now];return max( query( lson, l, mid, L, R ), query( rson, mid + 1, r, L, R ) );}
}namespace MinSgt {int Min[maxn << 2];void build( int now, int l, int r ) {Min[now] = n + 1;if( l == r ) return;build( lson, l, mid );build( rson, mid + 1, r );}void modify( int now, int l, int r, int p, int v ) {if( l == r ) { Min[now] = v; return; }if( p <= mid ) modify( lson, l, mid, p, v );else modify( rson, mid + 1, r, p, v );Min[now] = min( Min[lson], Min[rson] );}int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return n + 1;if( L <= l and r <= R ) return Min[now];return min( query( lson, l, mid, L, R ), query( rson, mid + 1, r, L, R ) );}
}struct tree {vector < int > G[maxn];int f[maxn][17]; ll g[maxn][17];void addedge( int u, int v ) {G[u].push_back( v );}int Fabs( int x ) {return x < 0 ? -x : x;}void dfs( int u, int fa ) {f[u][0] = fa, g[u][0] = 1ll * Fabs( u - fa ) * b[a[u]]; for( int i = 1;i < 17;i ++ ) {f[u][i] = f[f[u][i - 1]][i - 1];g[u][i] = g[f[u][i - 1]][i - 1] + g[u][i - 1];}for( int i = 0;i < G[u].size();i ++ ) dfs( G[u][i], u );}
}L, R;void AddR( int l, int r ) {for( int i = 16;~ i;i -- )if( L.f[r][i] >= l ) ans += L.g[r][i], r = L.f[r][i];ans += 1ll * (r - l + 1) * b[a[r]];
}void SubR( int l, int r ) {for( int i = 16;~ i;i -- )if( L.f[r][i] >= l ) ans -= L.g[r][i], r = L.f[r][i];ans -= 1ll * (r - l + 1) * b[a[r]];
} void AddL( int l, int r ) {for( int i = 16;~ i;i -- )if( R.f[l][i] <= r ) ans += R.g[l][i], l = R.f[l][i];ans += 1ll * (r - l + 1) * b[a[l]];
}void SubL( int l, int r ) {for( int i = 16;~ i;i -- )if( R.f[l][i] <= r ) ans -= R.g[l][i], l = R.f[l][i];ans -= 1ll * (r - l + 1) * b[a[l]];
}void read( int &x ) {x = 0; int f = 1; char s = getchar();while( s < '0' or s > '9' ) {if( s == '-' ) f = -1; s = getchar();}while( '0' <= s and s <= '9' ) {x = (x << 1) + (x << 3) + (s ^ 48);s = getchar();}x *= f;
}void print( ll x ) {if( x < 0 ) putchar('-'), x = -x;if( x > 9 ) print( x / 10 );putchar( x % 10 + '0' );
}int main() {read( n ), read( Q );B = 400;for( int i = 1;i <= n;i ++ ) read( a[i] );for( int i = 1;i <= Q;i ++ ) read( q[i].l ), read( q[i].r ), q[i].id = i;for( int i = 1;i <= n;i ++ ) block[i] = (i - 1) / B + 1;sort( q + 1, q + Q + 1, []( query x, query y ) { return (block[x.l] == block[y.l]) ? (x.r < y.r) : (x.l < y.l); } );for( int i = 1;i <= n;i ++ ) b[i] = a[i];sort( b + 1, b + n + 1 );int m = unique( b + 1, b + n + 1 ) - b - 1;for( int i = 1;i <= n;i ++ ) a[i] = lower_bound( b + 1, b + m + 1, a[i] ) - b;for( int i = 1;i <= n;i ++ ) {lst[i] = MaxSgt :: query( 1, 1, m, 1, a[i] );MaxSgt :: modify( 1, 1, m, a[i], i );L.addedge( lst[i], i );}MinSgt :: build( 1, 1, m );for( int i = n;i >= 1;i -- ) {nxt[i] = MinSgt :: query( 1, 1, m, 1, a[i] );MinSgt :: modify( 1, 1, m, a[i], i );R.addedge( nxt[i], i );}L.dfs( 0, 0 );R.dfs( n + 1, n + 1 );int curl = 1, curr = 0;for( int i = 1;i <= Q;i ++ ) {int l = q[i].l, r = q[i].r;while( curr < r ) AddR( curl, ++ curr );while( curr > r ) SubR( curl, curr -- );while( curl > l ) AddL( -- curl, curr );while( curl < l ) SubL( curl ++, curr );ret[q[i].id] = ans;}for( int i = 1;i <= Q;i ++ ) print( ret[i] ), putchar('\n');return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cf1523C. Compression and Expansion

cf1523C. Compression and Expansion 题意&#xff1a; 让你模拟出一个书的目录&#xff0c;对于每一行给你一个数字&#xff0c;表示这个目录的最后一个数&#xff0c; 题解&#xff1a; 我们用vector存当前的目录情况&#xff0c;读到下一行&#xff0c;在尽量少删上一行…

《从零开始学ASP.NET CORE MVC》:ASP.NET Core 中的 Main方法(5)

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core Web 项目文件ASP.NET Core 中的 Main方法一个开始专心写字的人在ASP.NET Core项目中&#xff0c;我们有一个名为Program.cs的文件。在这个文件中&#xff0c;我们有一个public static void Main&#…

[HNOI2016] 大数(莫队)

problem luogu-P3245 solution 将这个 nnn 位数从右往左的记录取模 ppp 的结果&#xff0c;即 f(i)(f(i−1)∗10si)%pf(i)(f(i-1)*10s_i)\% pf(i)(f(i−1)∗10si​)%p。 显然一个子串是 ppp 的倍数必然满足&#xff1a;f(r)−f(l−1)10r−l1≡0(modp)\frac{f(r)-f(l-1)}{10…

2021牛客暑期多校训练营9

2021牛客暑期多校训练营9 题号题目知识点AA Math ChallengeBBest SubgraphCCellsDDivide-and-conquer on TreeEEyjafjallaFFinancial Order ExecutionGGlass BallsHHappy NumberIIncentive ModelJJam

.NET中的状态机库Stateless

标题&#xff1a;.NET中的状态机库Stateless 作者&#xff1a;Lamond Lu 地址&#xff1a;https://www.cnblogs.com/lwqlun/p/10674018.html[1]介绍什么是状态机和状态模式状态机是一种用来进行对象建模的工具&#xff0c;它是一个有向图形&#xff0c;由一组节点和一组相应的转…

[APIO2016] 划艇(dp + 组合数 + 前缀和优化)

problem luogu-P3643 solution 有个显然的暴力 dpdpdp。设 dp(i,j):dp(i,j):dp(i,j): 到了第 iii 个学校&#xff0c;其参加且派出 jjj 个划艇的方案数。 枚举上一个参加的学校以及派出的划艇&#xff0c;则有转移&#xff1a;dp(i,j)∑k<i,j<jdp(k,j′)dp(i,j)\sum_…

.net core webapi 前后端开发分离后的配置和部署

背景&#xff1a;现在越来越多的企业都采用了在开发上前后端分离&#xff0c;前后端开发上的分离有很多种&#xff0c;那么今天&#xff0c;我来分享一下项目中得的前后端分离。B/S Saas 项目&#xff1a;&#xff08;这个项目可以理解成个人中心&#xff0c;当然不止这么点功…

Happy Number

Happy Number 题意 &#xff1a; 开心数是由仅由2&#xff0c;3&#xff0c;6组成的&#xff0c;问第n个开心数是哪个&#xff1f; 1<n<1e9 题解&#xff1a; 正解应该是&#xff1a; 首先确定k大数有几位&#xff1a; 然后就知道k大数是x位下的第k’大的 把2看成0&a…

[HNOI2015] 接水果(倍增 + 整体二分)

problem luogu-P3242 solution 本题的难点在于如何判定路径之间是否覆盖。 这里我们尝试树常见的 dfs\text{dfs}dfs 序。 考虑 x−yx-yx−y 路径如果要覆盖 u−vu-vu−v 路径需要满足怎样的条件。 以下均假设 dfs(u)<dfs(v),dfs(x)<dfs(y)dfs(u)<dfs(v),dfs(x)&…

ASP.NET Core使用Jaeger实现分布式追踪

前言最近我们公司的部分.NET Core的项目接入了Jaeger&#xff0c;也算是稍微完善了一下.NET团队的技术栈。至于为什么选择Jaeger而不是Skywalking&#xff0c;这个问题我只能回答&#xff0c;大佬们说了算。前段时间也在CSharpCorner写过一篇类似的介绍Exploring Distributed T…

[SCOI2007] 修车(费用流 + 差分时间段建图)

problem luogu-P2053 solution 假设只有一个工作人员。修车顺序为 p1,p2,...,pnp_1,p_2,...,p_np1​,p2​,...,pn​ 是一个 nnn 的排列。 那么对于第 iii 个被修的车的等待时间应为 Tp1...TpiT_{p_1}...T_{p_i}Tp1​​...Tpi​​。 总的等待时间则是 Tp1(Tp1Tp2)...(Tp1..…

长沙开发者技术大会暨.NET技术社区成立大会倒数第13天

待你扬帆起航&#xff0c;一起精彩纷呈&#xff01;长沙开发者技术大会暨.NET技术社区成立大会倒数第13天&#xff01;2019年4月21日期待与你相聚在.NET技术社区&#xff01;我们今天会完成海报制作和报表表单&#xff0c;海报内容初步如下所示&#xff1a;活动信息 长沙开发者…

[TJOI2011] 卡片(网络流 + 质因子优化建图)

problem luogu-P2065 solution 这个拿走一组共两张卡片的操作其实就是一个匹配。 直接两个数的最大公约数大于 111 就建一条边&#xff0c;跑二分图匹配最大流即可。 然而如果直接枚举两个数然后算他们的 gcd\text{gcd}gcd &#xff0c;时间复杂度 O(Tn2log⁡V)O(Tn^2\log…

C#并行编程(1):理解并行

什么是并行并行是指两个或者多个事件在同一时刻发生。在程序运行中&#xff0c;并行指多个CPU核心同时执行不同的任务&#xff1b;对于单核心CPU,严格来说是没有程序并行的。并行是为了提高任务执行效率&#xff0c;更快的获取结果。与并发的区别&#xff1a;并发是指两个或者多…

P2163 [SHOI2007]园丁的烦恼(二维数点模板题)

P2163 [SHOI2007]园丁的烦恼 题意&#xff1a; 在一个二维平面内有一些点&#xff0c;给你一个左上角和右下角的点&#xff0c;问这个范围内有多少点 题解&#xff1a; 二维数点模板题 我们设F(a,b)表示以(0,0)为左下角&#xff0c;(a,b)为右上角的矩阵内有多少点 如图不难…

[CQOI2017] 小Q的表格(分块 + 整除分块 + 数学 + 前缀和)

problem luogu-P3700 solution f(a,b)f(b,a)f(a,b)f(b,a)f(a,b)f(b,a) 意味着我们只用考虑半个棋盘的信息。 b∗f(a,ab)(ab)∗f(a,b)b*f(a,ab)(ab)*f(a,b)b∗f(a,ab)(ab)∗f(a,b) 会发现修改 f(a,b)f(a,b)f(a,b) 就影响 f(a,ab)f(a,ab)f(a,ab) 进而影响 f(a,a2b)…f(a,a2b)\…

Orleans MultiClient 多个Silo复合客户端

介绍Orleans.MultiClient 是一个 Orleans 复合客户端&#xff0c;只需要简单配置就可以简单高效连接和请求 Orleans 服务。Orleans.MultiClient 可以轻松连接多个不同服务的 Orleans 服务,在请求 Orleans 时会根据请求的接口自动寻找 Orleans 客户端&#xff0c;使用者无需关心…

[kuangbin]各种各样的题单

[kuangbin]各种各样的题单 专题1 简单搜索 POJ 1321 POJ 2251 POJ 3278 POJ 3279 POJ 1426 POJ 3126 POJ 3087 POJ 3414 FZU 2150 UVA 11624 POJ 3984 HDU 1241 HDU 1495 HDU 2612 专题2 搜索进阶 HDU 1043 HDU 3567 HDU 2181 HDU 3533 HDU 1560 ZOJ 2477 HDU 3085 HDU 1067 HD…

[CQOI2017] 小Q的棋盘(贪心 / 树形dp)

problem luogu-P3698 solution1-贪心 显然我们想尽可能地少走回头路&#xff0c;即一直往下走。 所以我们可以都会有个初步地猜测是走最长链。 但很快就会想到万一这是一条单链&#xff0c;链中的点都是二度点&#xff0c;走得越深回头浪费的步数也越多。 然后就可能直接…

ASP.NET Core 进程内(InProcess)托管(6)《从零开始学ASP.NET CORE MVC》:

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core 中的 Main方法ASP.NET Core 进程内(InProcess)托管在这个视频中我们将讨论在ASP.NET Core中的进程内(InProcess)托管模型什么是Kestrel服务器当一个 ASP.NET Core 应用程序执行的时候&#xff0c;.NET…