LOJ 题面传送门

orz 斜率优化……

模拟赛时被这题送走了,所以来写篇题解(

首先这个最短路的求法是 trivial 的,直接一遍 dijkstra 即可(

重点在于怎样求第二问。注意到这个第二问平方和最大要在保证最短路的基础上求,因此考虑建出最短路 DAG,这样最短路径上一条 \(1\to n\) 的路径就对应原图中一条最短路。因此此题等价于求一条 \(1\to n\) 的路径,满足每一个属于同一连续段上路径权值和的平方之和最大。注意到 \(f(x)=x^2\) 是下凸函数,也就是对于一段同一铁路线上的路径,我们肯定不会选择将它们拆成一段段小路径。因此我们考虑这样一个 \(dp\):\(dp_i\) 表示从 \(1\to i\) 路径上每一段权值之和的平方之和的最大值,转移就枚举上一次乘坐的那段铁路线的起始城市 \(j\),由于是最短路径 DAG,必然有这一段路径的长度为 \(dis_j-dis_i\),因此有转移 \(dp_i=\max\{dp_j+(dis_j-dis_i)^2\}\)。

直接做是 \(\sum s_i^2\) 的无法通过,考虑怎样优化。考虑将平方拆开来得到 \(dp_i=\max\{dp_j+dis_j^2-2dis_idis_j\}+dis^2_i\),这东西等价于平面上有若干个形如 \((dis_j,dp_j+dis_j^2)\) 的点,现在你要过这些点分别做斜率 \(2dis_i\) 的直线并取最大截距。我们考虑对所有铁路线维护这些点组成的上凸包,查询就直接在凸包中二分找斜率为 \(2dis_i\) 的直线也可以。当然也有线性的维护方法,注意到此题我们需维护上凸包,凸包中直线斜率递减,并且在拓扑排序的过程中我们查询的直线的斜率 \(2dis_i\) 肯定是递增的,因此每查询一条直线毙掉的凸包中的直线肯定一段后缀,也就是最新加入的某一些直线,因此需用单调栈维护。复杂度 \(n\log n\)。

const int MAXN=1e6;
int n,m,hd[MAXN+5],to[MAXN+5],nxt[MAXN+5],val[MAXN+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;val[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
vector<pii> tr[MAXN+5],pos[MAXN+5];
vector<int> bel[MAXN+5];
ll dis[MAXN+5],dp[MAXN+5];
int ord[MAXN+5],bcnt=0;
bool cmp(int x,int y){return dis[x]<dis[y];}
ld slope(int x,int y){return 1.0*((dis[x]*dis[x]+dp[x])-(dis[y]*dis[y]+dp[y]))/(dis[x]-dis[y]);}
vector<int> stk[MAXN*2+5];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int cnt,x;scanf("%d%d",&cnt,&x);
tr[i].pb(mp(x,0));int pre=x;pos[x].pb(mp(i,0));
for(int j=1;j<=cnt;j++){
int w,y;scanf("%d%d",&w,&y);
tr[i].pb(mp(y,w));pos[y].pb(mp(i,j));
adde(pre,y,w);pre=y;
} bel[i].resize(cnt+2);
} memset(dis,63,sizeof(dis));dis[1]=0;
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
q.push(mp(0,1));
while(!q.empty()){
pair<ll,int> p=q.top();q.pop();int x=p.se;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];
if(dis[y]>dis[x]+z){
dis[y]=dis[x]+z;
q.push(mp(dis[y],y));
}
}
}
for(int i=1;i<=n;i++) ord[i]=i;
sort(ord+1,ord+n+1,cmp);
for(int i=1;i<=m;i++) bel[i][0]=++bcnt;
for(int i=1;i<=n;i++){
int x=ord[i];//printf("%d\n",x);
for(pii p:pos[x]){
int id=p.fi,t=p.se;if(!t) continue;
int pre=tr[id][t-1].fi;
if(dis[x]==dis[pre]+tr[id][t].se) bel[id][t]=bel[id][t-1];
else bel[id][t]=++bcnt;
// printf("%d %d %d %d\n",x,id,t,bel[id][t]);
if(bel[id][t]==bel[id][t-1]){
int b=bel[id][t];
assert(!stk[b].empty());
while(stk[b].size()>=2&&slope(stk[b][stk[b].size()-1],stk[b][stk[b].size()-2])<2*dis[x]) stk[b].ppb();
int y=stk[b].back();chkmax(dp[x],dp[y]+(dis[x]-dis[y])*(dis[x]-dis[y]));
}
}
for(pii p:pos[x]){
int id=p.fi,t=p.se,b=bel[id][t];
// printf("ins %d\n",b);
while(stk[b].size()>=2&&slope(stk[b][stk[b].size()-1],stk[b][stk[b].size()-2])<
slope(stk[b][stk[b].size()-1],x)) stk[b].ppb();
stk[b].pb(x);
}
} printf("%lld %lld\n",dis[n],dp[n]);
return 0;
}

LOJ #2769 -「ROI 2017 Day 1」前往大都会(单调栈维护斜率优化)的更多相关文章

  1. Loj#2769-「ROI 2017 Day 1」前往大都会【最短路树,斜率优化】

    正题 题目链接:https://loj.ac/p/2769 题目大意 给出\(n\)个点\(m\)条地铁线路,每条线路是一条路径. 求\(1\)到\(n\)的最短路且在最短路径的情况下相邻换乘点的距离 ...

  2. [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞

    [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...

  3. loj #6250. 「CodePlus 2017 11 月赛」找爸爸

    #6250. 「CodePlus 2017 11 月赛」找爸爸 题目描述 小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对. 小 A 有一套自己的 DNA 序列比较方法,其最终目标是最 ...

  4. [LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

    Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不 ...

  5. [LOJ 6248]「CodePlus 2017 11 月赛」晨跑

    Description “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不 ...

  6. loj 2392「JOISC 2017 Day 1」烟花棒

    loj 答案显然满足二分性,先二分一个速度\(v\) 然后显然所有没有点火的都会往中间点火的人方向走,并且如果两个人相遇不会马上点火,要等到火快熄灭的时候才点火,所以这两个人之后应该在一起行动.另外有 ...

  7. loj#2391 「JOISC 2017 Day 1」港口设施

    分析 https://yhx-12243.github.io/OI-transit/records/uoj356%3Bloj2391%3Bac2534.html 代码 #include<bits ...

  8. LOJ 2288「THUWC 2017」大葱的神力

    LOJ 2288「THUWC 2017」大葱的神力 Link Solution 比较水的提交答案题了吧 第一个点爆搜 第二个点爆搜+剪枝,我的剪枝就是先算出 \(mx[i]\) 表示选取第 \(i \ ...

  9. Loj #2731 「JOISC 2016 Day 1」棋盘游戏

    Loj 2731 「JOISC 2016 Day 1」棋盘游戏 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少 ...

随机推荐

  1. Golang通脉之包的管理

    在工程化的开发项目中,Go语言的源码复用是建立在包(package)基础之上的. 包(package)是多个Go源码的集合,是一种高级的代码复用方案,Go语言提供了很多内置包,如fmt.os.io等. ...

  2. 【UE4】基础概念——文件结构、类型、反射、编译、接口、垃圾回收、序列化

    新标签打开或者下载看大图 思维导图 Engine Structure Pipeline Programming Pipeline Blueprint Pipeline

  3. BUAA 2020 软件工程 提问回顾与个人总结

    BUAA 2020 软件工程 提问回顾与个人总结 Author: 17373051 郭骏 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾 ...

  4. (数据科学学习手札129)geopandas 0.10版本重要新特性一览

    本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在前不久,我们非常熟悉的Python地理 ...

  5. 攻防世界 杂项 5.wireshark-1

    题目描述: 黑客通过wireshark抓到管理员登陆网站的一段流量包(管理员的密码即是答案). flag提交形式为flag{XXXX} 看到登录应该想到它是HTTP POST请求,wireshark搜 ...

  6. 确定两串乱序同构 牛客网 程序员面试金典 C++ Python

    确定两串乱序同构 牛客网 程序员面试金典 C++ Python 题目描述 给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串.这里规定大小写为不同字符,且考虑字符串中 ...

  7. Code Runner,率先支持刚发布的 Visual Studio 2022!

    Visual Studio 被不少网友成为"宇宙第一IDE".但是,我写✍ PHP.Java 和 C#,也都是用的 VS Code. 我所在的组,是 Visual Studio C ...

  8. [python]django关闭debug

    1.版本声明 python3.6.5 django2.0.6 2.打开项目-setting setting.py中DEBUG默认是等于True,这样的话当访问接口存在错误会直接展示项目的所有配置信息, ...

  9. mysql批量修改某一列的值为另外的值

    sql语句 UPDATE tb_info SET org_id = 2170 WHERE org_id = 815

  10. java eclipse调试提示Source not found 或 一闪而过 解决方法

    Web工程Eclipse  debug方式启动,在断点的位置被成功拦截,但是没有跳转到工程的代码处,提示如下: 当然这个时候如果我继续按F5的话呢,程序又会接着正常运行了.到这里那就是说程序本身是没有 ...