Portal -->bzoj3672

Solution

  天知道我是怎么调完的qwq调到天昏地暗系列。。

​  

  不管这么多,先尝试列一个最简单的状态转移方程

  用\(f[i]\)表示\(i\)点到\(1\)号点要花费的最少资金,\(dis[i]\)表示\(i\)到\(1\)号点的距离,那么有:
\[ f[i]=min(f[j]+p[i]*(dis[i]-dis[j])+q[i]) \]
  其中\(j\)是\(i\)的祖先且\(dis[i]-dis[j]<=l[i]\)

​  然后直接转移什么的肯定是不现实的啦。。所以我们可以先看看dp本身可以用什么优化

​  首先这个转移式子,我们换一个方式来写一下:
\[ f[j]=p[i]*dis[j]+(f[i]-p[i]*dis[i]+q[i]) \]
​  当考虑\(i\)的时候,\(-p[i]*dis[i]+q[i]\)可以看成一个常数,\(p[i]\)也可以看成一个常数,那么上面这个式子可以看成\(y=kx+b\)的形式,也就是说,是一条斜率为\(p[i]\),截距为\((f[i]-p[i]*dis[i]+q[i])\)的直线

  然后我们可以考虑斜率优化啦,因为斜率不是单调的所以还是要老老实实在凸包上二分,然后这里我们要\(f[i]\)最小所以是维护下凸壳

  

  然而

​  这题的dp在树上。。而且还有两个限制条件(\(lca(i,j)=j\)且\(dis[i]-dis[j]<=l[i]\))

​  关于\(lca(i,j)=j\)这个条件,自己一开始有一个比较初步的想法是每次用这个点去更新其子树还想着写线段树然后再每个区间维护凸包什么之类的。。然而实际上这里有一种比较高级的姿势:

​  树上cdq分治(emm大神的博客里面是这么叫的)

​   

​  这里的cdq分治的话,大致的过程是(其实写起来跟点分差不多的。。看到网上也有大神说这个就是点分。。):

1、找一个点\(x\)将树分为上下两个部分(为了保证复杂度这里的\(x\)显然应该要找重心)

2、先递归处理这个点\(x\)以上的(也就是包含当前根节点的)那一部分(相当于一般cdq的处理左边区间)

3、用上一步中处理出来的\(x\)的祖先的信息来更新\(x\)的子树(相当于统计左边对右边贡献)

4、递归处理\(x\)的子树(处理右边)

​  

​  这样我们就解决了\(lca(i,j)=j\)的问题,接下来是第二个限制\(dis[i]-dis[j]<=l[i]\)

​  我们稍微处理一下这个不等式,变成:\(dis[i]-l[i]<=dis[j]\)

​  现在我们考虑用不同的\(j\)去更新\(i\)(就是步骤3中用祖先更新子树)

  因为\(dis\)是单调的,我们可以在更新之前先排个序,子树内的点按照\(dis[i]-l[i]\)从大到小排,\(dis[j]\)也是从大到小(其实两个都反过来也是可以的,只是因为我在程序里面写的时候求祖先是暴力跳的,所以祖先的\(dis\)求出来就是从大到小的顺序,所以就这么写了)

​  我们按顺序枚举祖先,每次在将当前枚举到的祖先\(j\)加到凸包里面去之前,先判断一下当前的\(dis[i]-l[i]\)是否\(<=dis[j]\),如果不是的话,那么就在还没有加入祖先\(j\)的凸包中二分来更新\(f[i]\),然后再将祖先\(j\)加入凸包;否则直接将\(j\)加入凸包

​  这里因为\(dis\)(也就是凸包上点的\(x\)坐标)是单调的所以可以直接单调栈维护

​  这样就能保证我们在凸包中二分出来的答案一定是满足\(dis[i]-dis[j]<=l[i]\)的

​  然后就非常愉悦地做完了,总的复杂度是\(O(nlog^2n)\)

​  

  一些可能要注意的细节&自己跳进去的坑:

1、本来凸包是写的叉积的。。但是后来看了一下数据范围有点担心\(x*y\)一下直接爆longlong了。。所以就改成斜率了。。还是要注意一下可能会出现两个\(x\)相等的情况所以要判一下避免除以\(0\)(之前那个坑爬得太艰难再也不相信除法了qwq)

2、注意是下凸壳下凸壳下凸壳!(调着调着把自己调懵了系列。。)

3、建凸包的时候注意祖先是按照\(dis\)从大到小来排的。。也就是横坐标是递减的。。

4、看清数据范围。。各种long long

​  

​  代码大概长这个样子(思路好像不算特别绕但是。。调起来就很。。了。。)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=2*(1e5)+10;
const ll inf=1LL<<60;
struct xxx{int y,nxt;
}a[MAXN*2];
int h[MAXN],sz[MAXN],vis[MAXN],mx[MAXN],pre[MAXN];
int rec[MAXN],st[MAXN],rec_pre[MAXN];
ll p[MAXN],q[MAXN],l[MAXN],dis[MAXN];
ll f[MAXN];
int n,m,tot,rt,rt_mx,All,T;
void add(int x,int y);
void get_sz(int fa,int x);
void get_rt(int All,int fa,int x);
void dfs(int fa,int x);
void solve(int x,int All);
bool cmp(int x,int y){return dis[x]-l[x]>dis[y]-l[y];}
void update(int x,int top);
ll X(int i){return dis[i];}
ll Y(int i){return f[i];}
double get_k(int i,int j){if (X(i)==X(j)) return inf; return (1.0*(Y(i)-Y(j)))/(1.0*(X(i)-X(j)));}int main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);
#endifscanf("%d%d\n",&n,&T);memset(h,-1,sizeof(h));tot=0;for (int i=2;i<=n;++i){scanf("%d%lld%lld%lld%lld\n",pre+i,dis+i,p+i,q+i,l+i);dis[i]+=dis[pre[i]];add(pre[i],i);}for (int i=1;i<=n;++i) f[i]=inf;f[1]=0;solve(1,n);for (int i=2;i<=n;++i) printf("%lld\n",f[i]);
}void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;
}void get_sz(int fa,int x){int u;sz[x]=1; mx[x]=0;for (int i=h[x];i!=-1;i=a[i].nxt){u=a[i].y;if (u==fa||vis[u]) continue;get_sz(x,u);sz[x]+=sz[u];mx[x]=max(mx[x],sz[u]);}
}void get_rt(int All,int fa,int x){mx[x]=max(mx[x],All-sz[x]);if (mx[x]<=rt_mx) rt=x,rt_mx=mx[x];int u;for (int i=h[x];i!=-1;i=a[i].nxt){u=a[i].y;if (u==fa||vis[u]) continue;get_rt(All,x,u);}
}void solve(int x,int All){int u,Rt;rt=-1,rt_mx=n;get_sz(0,x);get_rt(All,0,x);vis[rt]=1;Rt=rt;//处理上面的部分(如果有的话)if (Rt!=x)solve(x,All-sz[Rt]);//记录子树中的点并排好序   rec[0]=0;for (int i=h[Rt];i!=-1;i=a[i].nxt)if (!vis[a[i].y]) dfs(x,a[i].y);sort(rec+1,rec+1+rec[0],cmp);//记录祖先(本身处理出来就是有序的了)rec_pre[0]=1; rec_pre[1]=Rt;for (int i=Rt;i!=x;i=pre[i]){if (dis[Rt]-dis[pre[i]]<=l[Rt])f[Rt]=min(f[Rt],f[pre[i]]+p[Rt]*(dis[Rt]-dis[pre[i]])+q[Rt]);rec_pre[++rec_pre[0]]=pre[i];}//统计祖先对子树中点的贡献int top=0,tot=1;for (int i=1;i<=rec_pre[0];++i){while (tot<=rec[0]&&dis[rec[tot]]-dis[rec_pre[i]]>l[rec[tot]])update(rec[tot],top),++tot;while (top>1&&get_k(st[top-1],rec_pre[i])<=get_k(st[top],rec_pre[i])) //down--top;st[++top]=rec_pre[i];}while (tot<=rec[0]) update(rec[tot],top),++tot;//递归处理子树for (int i=h[Rt];i!=-1;i=a[i].nxt){if (!vis[a[i].y])solve(a[i].y,sz[a[i].y]);}
}void dfs(int fa,int x){int u;rec[++rec[0]]=x;for (int i=h[x];i!=-1;i=a[i].nxt){u=a[i].y;if (u==fa||vis[u]) continue;dfs(x,u);}
}void update(int i,int top){if (!top) return;int l=1,r=top-1,mid,ret=top,j,k;while (l<=r){mid=l+r>>1;j=st[mid];k=st[mid+1];if ((f[j]-f[k])<=p[i]*(dis[j]-dis[k])) ret=mid,r=mid-1;else l=mid+1;}ret=st[ret];f[i]=min(f[i],f[ret]+p[i]*(dis[i]-dis[ret])+q[i]);
}

转载于:https://www.cnblogs.com/yoyoball/p/9250575.html

【bzoj3672】购票相关推荐

  1. bzoj-3672 购票

    题意: 给出一颗n个结点的有根树,边有长度: 每个点有可以购票前往长度相差不超过li的它的祖先,票的花费为pi*长度+qi: 当然的,可以的选择多次倒车到达: 求每个点到根的最小花费: n<=2 ...

  2. 【BZOJ3672】[Noi2014]购票 树分治+斜率优化

    [BZOJ3672][Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构 ...

  3. CCF CSP 201609-2 火车购票

    题目链接:http://118.190.20.162/view.page?gpid=T46 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排 ...

  4. 【青少年编程】【蓝桥杯】排队购票

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 我们将有关编程题目的教学视频已经发布到抖 ...

  5. 铁路网上购票需要完善但值得鼓励

    这几天,春运购票成了头等大事,而今年铁道部实行的网上购票和电话购票也改变了此前火车站排长队熬夜的痛苦现状.不过,也有人给铁道部写公开信,经由媒体报道后,一些人对铁路的此项具有深远意义的改革进行批判挖苦 ...

  6. CCF CSP 201609-2 火车购票(90分,怎么也检查不出来问题在哪儿,导致不能满分??)

    问题描述 试题编号: 201609-2 试题名称: 火车购票 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配 ...

  7. 春运又在路上了,火车购票、出行指南了解一下!

    近日,中国铁路广州局集团正式启动2021年春运外来工团体订票.交通运输部本月也宣布已启动春运筹备工作.一年一度的春运大幕已经缓缓拉开. 铁路出行作为春运的一种主要方式,不同群体购票时有哪些注意事项,这 ...

  8. 为什么同样是上亿的并发,购票系统就要比电商系统技术挑战更大?

    同为高并发,微博热搜.天猫秒杀.12306 抢票有什么不同呢? 那接下来我们就来分别聊聊他们有什么特性~ 1.微博热搜 「微博热搜」是一个典型的读多写少场景,读今日的热点新闻,写自己的微博评论. 作为 ...

  9. 语音购票、刷脸进站:上海联手阿里打造全球首个AI地铁之城

    对着售票机喊句话就能买到地铁票?这个在过去看来完全无法想象的事,在阿里的黑科技加持下已成现实. 12月5日,语音购票.刷脸进站.智能客流监测等多项"黑科技"首度惊艳亮相上海.这三项 ...

最新文章

  1. 数据库更新记录,但程序查不到新记录问题
  2. 微服务如何解决分布式事务
  3. .process和ProcessFunction(没有整理完)
  4. Java引用类型变量如何分配内存空间?
  5. Arrays.sort()用来自定义排序的使用
  6. [知识整理]Linux系统WIFI知识的一些整理
  7. Python的内置函数的学习笔记
  8. 去年出货的工业机器人,超过1/3都跑来了中国
  9. Mpass – PHP做Socket服务的解决方案
  10. 打印机服务器属性纸张自动改,“打印机设置自定义纸张”的解决方案
  11. 台式计算机总是重启,电脑为什么老是自动重启?我的电脑经常自动重启!!
  12. 黑色渐变遮罩html,巧用CSS遮罩
  13. 小红书商品详情API接口(商品详情页面数据接口)
  14. 计算机EI期刊2020,2020年Ei Compendex收录的中国期刊目录( JANUARY 1, 2020 )
  15. 【转】iOS开发人员必看的精品资料(100个)
  16. 记账软件 如何查看以往记录的所有收支明细
  17. 微软WHQL认证的好处
  18. linux slub分配器,Vi Linux内存 之 Slub分配器(六)
  19. 强化学习策略梯度方法之: REINFORCE 算法(从原理到代码实现)
  20. 学计算机类专业对电脑有要求,大学设计专业电脑配置须知

热门文章

  1. 有 OC 经验的程序员快速学习 Swift 语法
  2. html设置input圆角矩形_如何选择绘画尺寸、认识快捷键和设置快捷键
  3. 怎么选择网管型和非网管型交换机
  4. cameraraw预设_PS Camera Raw 导入预设以及分组
  5. Serverless Kubernetes 落地实践
  6. 从零入门 Serverless | 一文详解 Serverless 技术选型
  7. 国内首个 Kubernetes SIG-Cloud-Provider 子项目揭秘 | 云原生生态周报 Vol. 37
  8. python进行矩阵计算公式_纯python进行矩阵的相乘运算的方法示例
  9. navicat 怎么调试存储过程_Navicat 执行存储过程
  10. php 中空数据 用大括号,php语法设计 数组为什么不采用普遍的{}大括号呢? 其它的 编程语言 在数组初始值 都是 用大括号{} 包含的。...