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. Git浅析

    Git浅析 索引 Git的常用命令 GitHub的使用 Git版本创建和回退 Git的工作区和暂存区 Git分支管理 1-Git的常用命令 01.创建一个版本库--进入相应的目录 git init 可 ...

  2. Noip模拟41 2021.8.16

    T1 你相信引力吗 对于区间的大小关系问题,往往使用单调栈来解决 这道题的优弧和劣弧很烦,考虑将其等价的转化 由于所有的合法情况绕过的弧都不会经过最高的冰锥, 又因为环可以任意亲定起点,这样可以直接把 ...

  3. Pogo-Cow S

    这题出在单调队列优化dp里,就离谱好吧...... 对不住了上来先喷一波,不过离谱是确实的 dp的含义也很简单,就是说从j到i的分数最大值 直接上代马,里面说的很详细了 1 #include<b ...

  4. stm32电机控制之控制两路直流电机

    小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下: 由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动 ...

  5. linux下文件特殊权限设置位S和沾附位T(转载)

    今天在创建文件的时候,发现了文件权限末尾有个T,之前没留意过,后来又用c创建(open)了两个文件来查看,在我没有指定权限(省略open的第三个参数)的时候,有时还会出现S,虽然还没弄懂什么时候会出现 ...

  6. 无判断max 牛客网 程序员面试金典 C++ Python

    无判断max 牛客网  程序员面试金典 C++ Python 题目描述 请编写一个方法,找出两个数字中最大的那个.条件是不得使用if-else等比较和判断运算符. 给定两个int a和b,请返回较大的 ...

  7. Luogu P1654 OSU! | 期望

    题目链接 很妙的一道题. 题目要求$X^3$的期望值. 直接求不好求. 考虑先求出$X$和$X^2$的期望值,然后再求$X^3$的期望值. 迎.刃.而.解. #include<iostream& ...

  8. hdu 5093 Battle ships(二分图最大匹配)

    题意: M*N的矩阵,每个格子上是三个之一:*.o.#.                     (1 <= m, n <= 50) *:海洋,战船可以停在上面.      o:浮冰,战船 ...

  9. Harbor仓库搭建及使用

    目录 一.docker配置 二.安装docker-compose 三.安装harbor 四.管理harbor 五.springboot项目配置docker 六.linux服务器上打包并推送至harbo ...

  10. docker 使用报错的相关问题

    docker 创建本地主机实例Virtualbox 驱动报错,显示没有下载这个驱动 解决方案,下载virtuabox. https://www.cnblogs.com/effortday/p/1502 ...