[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,一经查实,立即删除!

相关文章

《从零开始学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&#…

.NET中的状态机库Stateless

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

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

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

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

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

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

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

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

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

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

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

Orleans MultiClient 多个Silo复合客户端

介绍Orleans.MultiClient 是一个 Orleans 复合客户端&#xff0c;只需要简单配置就可以简单高效连接和请求 Orleans 服务。Orleans.MultiClient 可以轻松连接多个不同服务的 Orleans 服务,在请求 Orleans 时会根据请求的接口自动寻找 Orleans 客户端&#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…

约会安排 HDU - 4553

约会安排 HDU - 4553 题意&#xff1a; 题意又丑又长就不叙述了 题解&#xff1a; 这个题一开始理解错了。。。题目相当于是有三种情况占据时间&#xff0c;分别是学习&#xff0c;女神和屌丝&#xff0c;我们用不同的lazy来表示女神和屌丝&#xff0c;根据优先级去更新状态…

ML.NET机器学习、API容器化与Azure DevOps实践(一):简介

打算使用几篇文章介绍一下.NET下的机器学习框架ML.NET的具体应用&#xff0c;包括一些常用的业务场景、算法的选择、模型的训练以及RESTful API的创建、机器学习服务容器化&#xff0c;以及基于Azure DevOps的容器化部署等等相关的内容。如果你从来没有玩过机器学习&#xff0c…

Picture POJ - 1177(矩形周长并))

Picture POJ - 1177 题目&#xff1a; 多个矩阵相交在一起&#xff0c;问新图形的周长是多少 题解&#xff1a; 参考题解 周长分为两部分&#xff1a;横线和竖线 横线计算方法&#xff1a;现在总区间被覆盖的长度和上一次总区间被覆盖的长度之差的绝对值 那么我们只需要从…

聊一聊C# 8.0中的await foreach

很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样.简单说,其实就是C# 8.0中支持await foreach.或者说,C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>>.好吧,还不懂?Good,这篇文章就是为你写的,看完这篇文章,你…

ASP.NET Core 实现带认证功能的Web代理服务器

引言最近在公司开发了一个项目&#xff0c;项目部署架构图如下&#xff1a;思路如图中文本所述&#xff0c;公司大数据集群不允许直接访问外网&#xff0c;需要一个网关服务器代理请求&#xff0c;本处服务器A就是边缘代理服务器的作用。通常技术人员最快捷的思路是在服务器A上…

Unfair contest(个人做法)

Unfair contest 题意&#xff1a; 两个人参赛&#xff0c;n个评委打分&#xff0c;去掉s个最高分&#xff0c;去掉t个最低分&#xff0c;剩下分求平均分&#xff0c;平均分大的获胜。你是第n个评委&#xff0c;此时已知前n-1个评委所打分数&#xff0c;现在轮到你打分&#x…

ASP.NET Core 进程外(out-of-process)托管(7)《从零开始学ASP.NET CORE MVC》

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core 进程内(InProcess)托管ASP.NET Core 进程内(InProcess)托管我们先简单回顾下 ASP.NET Core 中,要配置InProcess的服务器&#xff0c;需要在项目文件中添加< AspNetCoreHostingModel >元素&#…

eShopOnContainers 知多少[10]:部署到 K8S | AKS

1. 引言断断续续&#xff0c;感觉这个系列又要半途而废了。趁着假期&#xff0c;赶紧再更一篇&#xff0c;介绍下如何将eShopOnContainers部署到K8S上&#xff0c;进而实现大家常说的微服务上云。2. 先了解下 Helm读过我上篇文章ASP.NET Core 借助 K8S 玩转容器编排的同学&…

DI是实现面向切面和面向抽象的前提

DI越来越重要DI就是依赖注入&#xff0c;现在来说&#xff0c;大部分框架都是以DI为基础组件的&#xff0c;每一个框架都有自己的DI组件&#xff0c;像dotnet core&#xff0c;java spring等&#xff0c;也都为自己的框架量身打造了DI工具。面向对象的几个原则依赖倒置原则&…

.net core 并发下的线程安全问题

抱歉&#xff0c;其实内容并不如题&#xff01;&#xff01;&#xff01;背景&#xff08;写测试demo所出现的异常&#xff0c;供大家学习与拍砖&#xff09;&#xff1a;.net core webapi项目&#xff0c;做了一个授权的filter&#xff08;真正的生产项目的话&#xff0c;JWT很…

cf1555B. Two Tables

cf1555B. Two Tables 题意&#xff1a; 一个大矩阵空间内放置一个矩阵a&#xff0c;现在要再往这个空间内放一个矩阵b&#xff0c;a移动距离len才能放下b&#xff0c;问len最小是多少 题解&#xff1a; 不难发现左右或上下移动是最佳的&#xff0c;斜着移动是最不好的。此时…