几乎肝了半个下午和整个晚上

斜率优化的模型好多啊...

LOJ #2249 Luogu P2305


题意

给定一棵树,第$ i$个点如果离某个祖先$ x$的距离不超过$ L_i$,可以花费$ P_i·dist(i,x)+Q_i$的代价跳到点$ x$,

求每个点走到根的最小代价

点数不超过$ 2·10^5$


$ Solution$

用$dis_x$表示$ x$到根的距离

首先考虑一条链的情况

尝试斜率优化

容易推出两个点$j,k$,若$ dis_k>dis_j且k比j优$当且仅当$ \frac{dp_k-dp_j}{dis_k-dis_j}<P_i$

由于有$ P_i$不具有单调性可以维护单调栈然后每次在里面二分

但是由于有$ L_i$这个限制,这个单调栈并不容易直接维护

考虑$ CDQ$分治,即把问题转化成求左半部分对右半部分的转移贡献

将右半部分的点按照$ dis[i]-L_i$从大到小排序

每次枚举右边的点,将左边的点按距离从大到小加入单调栈中

显然现在没有$ L_i$的限制就可以直接在单调栈中二分

时间复杂度$ O(n \ log^2 \  n)$

然后就是把链上的问题放到树上

树上分治很容易想到直接点分治

流程如下:

1.找到当前子树的重心

2.将重心及重心外侧的子树递归计算(相当于序列上$CDQ$分治中的$calc(L,mid)$)

3.计算重心外侧的子树对重心以下的若干棵子树的贡献(相当于序列上$ CDQ$分治中左边对右边的贡献)

4.递归计算重心以下的各棵子树的答案(相当于序列上$ CDQ$分治中的$calc(mid+1,R)$)

总复杂度$ O(n \ log^2 \  n)$


$ my \ code$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define M 200010
#define rt register int
#define ll long long
using namespace std;
namespace fast_IO{
const int IN_LEN=,OUT_LEN=;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
inline ll read(){
ll x = ; char zf = ; char ch = getchar();
while (ch != '-' && !isdigit(ch)) ch = getchar();
if (ch == '-') zf = -, ch = getchar();
while (isdigit(ch)) x = x * + ch - '', ch = getchar(); return x * zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int i,j,k,m,n,x,y,z,cnt;
ll dis[M],lim[M],f[M],p[M],q[M];
int F[M],L[M],N[M],a[M],fa[M];
void add(int x,int y){
a[++k]=y;
if(!F[x])F[x]=k;
else N[L[x]]=k;
L[x]=k;
}
int size[],nowmin,all,Q[],sta[],top,Root,troot;
bool vis[];
inline bool cmp(int x,int y){return dis[x]-lim[x]>dis[y]-lim[y];}
inline double slope(int x,int y){return (double)(f[x]-f[y])/(dis[x]-dis[y]);}
void get(int x){
size[x]=;int maxsum=;
for(rt i=F[x];i;i=N[i])if(!vis[a[i]]){
get(a[i]);size[x]+=size[a[i]];
maxsum=max(maxsum,size[a[i]]);
}
maxsum=max(maxsum,all-size[x]+);
if(maxsum<nowmin)nowmin=maxsum,Root=x;
}
int len;
void dfs(int x){Q[++len]=x;for(rt i=F[x];i;i=N[i])if(!vis[a[i]])dfs(a[i]);}
void calc(int x,int sz){
if(sz<=)return;
nowmin=all=sz;get(x);int u=Root;
for(rt i=F[u];i;i=N[i])vis[a[i]]=;
calc(x,sz-size[u]+);len=;
for(rt i=F[u];i;i=N[i])dfs(a[i]);
sort(Q+,Q+len+,cmp);top=;
for(rt i=,pl=u;i<=len;i++){
while(dis[pl]>=dis[Q[i]]-lim[Q[i]]&&pl!=fa[x]){
while(top>=&&slope(pl,sta[top])>slope(sta[top],sta[top-]))top--;
sta[++top]=pl;pl=fa[pl];
}
f[Q[i]]=min(f[Q[i]],f[sta[top]]+(dis[Q[i]]-dis[sta[top]])*p[Q[i]]+q[Q[i]]);
if(top<=)continue;
int L=,R=top-;
while(L<=R){
const int mid=L+R>>;
if((f[sta[mid]]-f[sta[mid+]])<=p[Q[i]]*(dis[sta[mid]]-dis[sta[mid+]]))
R=mid-;else L=mid+;
}
f[Q[i]]=min(f[Q[i]],f[sta[L]]+(dis[Q[i]]-dis[sta[L]])*p[Q[i]]+q[Q[i]]);
}
for(rt i=F[u];i;i=N[i])calc(a[i],size[a[i]]);
}
int main(){
n=read();x=read();
memset(f,,sizeof(f));f[]=;
for(rt i=;i<=n;i++){
fa[i]=read();add(fa[i],i);
dis[i]=dis[fa[i]]+read();
p[i]=read();q[i]=read();lim[i]=read();
}
calc(,n);
for(rt i=;i<=n;i++)writeln(f[i]);
return flush(),;
}

LOJ#2249 Luogu P2305「NOI2014」购票的更多相关文章

  1. LOJ 2249: 洛谷 P2305: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

  2. 「NOI2014」购票 解题报告

    「NOI2014」购票 写完了后发现写的做法是假的...然后居然过了,然后就懒得管正解了. 发现需要维护凸包,动态加点,询问区间,强制在线 可以二进制分组搞,然后你发现在树上需要资瓷撤回,然后暴力撤回 ...

  3. 「NOI2014」购票

    「NOI2014」购票 解题思路 先列出 \(dp\) 式子并稍微转化一下 \[ dp[u] =\min(dp[v]+(dis[u]-dis[v]) \times p[u] + q[u])) \ \ ...

  4. LOJ 2249: 洛谷 P2305: bzoj 3672: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

  5. LOJ #2116 Luogu P3241「HNOI2015」开店

    好久没写数据结构了 来补一发 果然写的时候思路极其混乱.... LOJ #2116 Luogu P3241 题意 $ Q$次询问,求树上点的颜色在$ [L,R]$中的所有点到询问点的距离 强制在线 询 ...

  6. LOJ #2547 Luogu P4517「JSOI2018」防御网络

    好像也没那么难写 LOJ #2547 Luogu P4517 题意 在一棵点仙人掌中等概率选择一个点集 求选出点集的斯坦纳树大小的期望 定义点仙人掌为不存在一个点在多个简单环中的连通图 斯坦纳树为在原 ...

  7. LOJ #2527 Luogu P4491「HAOI2018」染色

    好像网上没人....和我推出....同一个式子啊..... LOJ #2527 Luogu P4491 题意 $ n$个格子中每个格子可以涂$ m$种颜色中的一种 若有$ k$种颜色恰好涂了$ s$格 ...

  8. 【LOJ】#2244. 「NOI2014」起床困难综合症

    题解 写水题放松一下心情 二进制有个很好的性质是每一位是独立的,我们按位贪心,先看这一位能不能填1,然后看看如果这一位填0那么运算后最后这一位是不是1,是的话就退出,然后看看这一位如果填1最后是1这一 ...

  9. LOJ#2244. 「NOI2014」起床困难综合症

    $n \leq 1e5$个位运算操作,$m \le 2^{30}$,问$0-m$中谁进行完所有操作值最大,输出这个最大值. cfA题难度?当送分题就不管了 and相当于几个位取0,or相当于几个位取1 ...

随机推荐

  1. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  2. 4.django学习模板

    ##引用模板 步骤: 在应用目录下创建templates目录,在目录下创建html文件 在views.py返回render(渲染) 1.requests请求本身,2.模板文件,3.后台传递到前端的数据 ...

  3. bzoj1497 最小割

    题意: 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前 ...

  4. 使用property为类中的数据添加行为

    对于面向对象编程特别重要的是,关注行为和数据的分离. 在这之前,先来讨论一些“坏”的面向对象理论,这些都告诉我们绝不要直接访问属性(如Java): class Color: def __init__( ...

  5. Spring下redis的配置

    这个项目用到redis,所以学了一下怎样在Spring框架下配置redis. 1.首先是在web.xml中添加Spring的配置文件. <web-app version="3.0&qu ...

  6. 机器学习算法 Python&R 速查表

    sklearn实战-乳腺癌细胞数据挖掘( 博主亲自录制) https://study.163.com/course/introduction.htm?courseId=1005269003&u ...

  7. python如何直接控制鼠标键盘

    一.简介 我们知道在windows下输入:win + r,会弹出下面的窗口,而在下面的窗口出现后我们接着按下esc键,下面的窗口会消失 现在设想我们想在python代码里控制键盘,想通过运行代码-&g ...

  8. docker 基础之私有仓库

    docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库.安装运行 docker-registry容器 在安装了 Docker 后,可以通过获取官方 registry 镜像来运行. ...

  9. powershell 定时删除脚本

    powershell  定时删除脚本 $today=Get-Date #"今天是:$today" #昨天 #"昨天是:$($today.AddDays(-1))" ...

  10. 深入浅出 JavaWeb:Servlet必会必知

    一.Web服务器 从事web开发的人,会很清楚一个东西叫HTTP服务器,比如JEE开发—Tomcat,Jetty,.NET开发—ISS等.HTTP服务器是使用 HTTP(超文本传输协议) 与客户机浏览 ...