[BZOJ3672][NOI2014]购票-点分治-CDQ分治-斜率优化DP
来源:互联网 发布:ubuntu更新内核命令 编辑:程序博客网 时间:2024/05/16 18:15
购票
Description
今年夏天,NOI在SZ市迎来了她30周岁的生日。来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会。
全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接。为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号。其中SZ市的编号为 1。对于除SZ市之外的任意一个城市 v,我们给出了它在这棵树上的父亲城市 fv 以及到父亲城市道路的长度 sv。
从城市 v 前往SZ市的方法为:选择城市 v 的一个祖先 a,支付购票的费用,乘坐交通工具到达 a。再选择城市 a 的一个祖先 b,支付费用并到达 b。以此类推,直至到达SZ市。
对于任意一个城市 v,我们会给出一个交通工具的距离限制 lv。对于城市 v 的祖先 a,只有当它们之间所有道路的总长度不超过 lv 时,从城市 v 才可以通过一次购票到达城市 a,否则不能通过一次购票到达。对于每个城市 v,我们还会给出两个非负整数 pv,qv 作为票价参数。若城市 v 到城市 a 所有道路的总长度为 d,那么从城市 v 到城市 a 购买的票价为 dpv+qv。
每个城市的OIer都希望自己到达SZ市时,用于购票的总资金最少。你的任务就是,告诉每个城市的OIer他们所花的最少资金是多少。
Input
第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 f_v,s_v,p_v,q_v,l_v,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。
Output
输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。
Sample Input
7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10
Sample Output
40
150
70
149
300
150
HINT
对于所有测试数据,保证 0 ≤ pv ≤ 106,0 ≤ qv ≤ 1012,1 ≤ fv < v;保证 0 < sv ≤ lv ≤ 2×1011,且任意城市到SZ市的总路程长度不超过 2×1011。
输入的 t 表示数据类型,0 ≤ t < 4,其中:
当 t=0 或 2 时,对输入的所有城市 v,都有 fv=v-1,即所有城市构成一个以SZ市为终点的链;
当 t=0 或 1 时,对输入的所有城市 v,都有 lv=2×1011,即没有移动的距离限制,每个城市都能到达它的所有祖先;
当 t=3 时,数据没有特殊性质。
n=2×10^5
论点分治学得不熟、CDQ分治和斜率优化十分钟前刚学会的NOIP选手马上用这三个方法去做题是一种什么感觉……
(╯‵□′)╯︵┻━┻
思路:
其实是一道思路很正常的题……
如果先不管距离限制,并且目标是一个序列,我们能得出一个简单粗暴的DP方程:
显然这个方程是在用祖先去更新儿子对吧……
然后我们试图进行斜率优化:
然后斜率优化居然就成功了……
那么考虑在树上,我们可以分治。
于是在点分治的基础上考虑用CDQ分治的更新方法维护斜率优化的凸包来降低复杂度。
因为刚才的DP是用祖先更新儿子,所以显然我们应该先把祖先搞定,再用祖先更新其儿子
具体分治方法是每次找出重心,先递归分治重心子树中含有原树根节点的那部分。
然后对其余子树内的节点全部按能走到的最小深度排序,也就是距根节点的距离减去其距离限制。
接着维护出重心到分治结构根节点这条链上的凸包,并一边维护一边用这个凸包更新子树内的DP值。
具体为对排序后的每个子树节点,以当前子树节点能否走到下一个链上的点为判断依据,来决定更新这个点时是否还能往凸包内加下一个链上的点,通过斜率来判断加一个点进凸包前是否需要弹点,然后在凸包上二分寻找最优值去更新这个子树节点。
最后直接递归分治其余子树,就可以了!
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;typedef double db;const int N=200009;const ll Inf=(1ll<<62);struct data{ int id; ll val;}a[N];bool operator <(data satori,data koishi){ return satori.val>koishi.val;}int n,t,cnt,stk[N];int fa[N],siz[N],msiz[N];int to[N<<1],nxt[N<<1],beg[N],tot;ll p[N],q[N],limit[N],dis[N],f[N],w[N<<1];bool ban[N];inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0' || '9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch && ch<='9'){x=x*10+(ch^48);ch=getchar();} return x*f;}inline void add(int u,int v,ll ww){ to[++tot]=v; nxt[tot]=beg[u]; w[tot]=ww; beg[u]=tot;}inline db slope(int i,int j){ return (f[j]-f[i])/(dis[j]-dis[i]);}void dfs(int u){ siz[u]=1; for(int i=beg[u],v;i;i=nxt[i]) { dis[v=to[i]]=dis[u]+w[i]; dfs(v); siz[u]+=siz[v]; }}void find(int u,int sum,int &root){ msiz[u]=0; siz[u]=1; for(int i=beg[u],v;i;i=nxt[i]) { if(ban[v=to[i]])continue; find(v,sum,root); siz[u]+=siz[v]; msiz[u]=max(msiz[u],siz[v]); } msiz[u]=max(msiz[u],sum-siz[u]); if(msiz[u]<msiz[root] && siz[u]>1) root=u;}void dfs2(int u){ a[++cnt].id=u; a[cnt].val=dis[u]-limit[u]; for(int i=beg[u];i;i=nxt[i]) if(!ban[to[i]]) dfs2(to[i]);}void solve(int x,int sum){ if(sum==1) return; int root=0; find(x,sum,root); for(int i=beg[root];i;i=nxt[i]) ban[to[i]]=1; solve(x,sum-siz[root]+1); cnt=0; for(int i=beg[root];i;i=nxt[i]) dfs2(to[i]); sort(a+1,a+cnt+1); int now=root,top; top=0; for(int i=1;i<=cnt;i++) { while(now!=fa[x] && dis[a[i].id]-limit[a[i].id]<=dis[now]) { while(top>=2 && slope(stk[top],now)>=slope(stk[top-1],stk[top])) top--; stk[++top]=now; now=fa[now]; } if(top) { int l=1,r=top,mid,ans=1; while(l<=r) { mid=l+r>>1; if(mid==top) { ans=top; break; } if(slope(stk[mid],stk[mid+1])>=p[a[i].id]) l=mid+1,ans=mid+1; else r=mid-1; } f[a[i].id]=min(f[a[i].id], f[stk[ans]]+(dis[a[i].id]-dis[stk[ans]])*p[a[i].id]+q[a[i].id]); } } for(int i=beg[root];i;i=nxt[i]) solve(to[i],siz[to[i]]);}int main(){ n=read(); ll v=read(); for(int i=2;i<=n;i++) { fa[i]=read();v=read(); add(fa[i],i,v); p[i]=read();q[i]=read(); limit[i]=read(); } dfs(1); msiz[0]=n+1; for(int i=2;i<=n;i++) f[i]=Inf; solve(1,siz[1]); for(int i=2;i<=n;i++) printf("%lld\n",f[i]); return 0;}
- [BZOJ3672][NOI2014]购票-点分治-CDQ分治-斜率优化DP
- 【NOI2014】【cdq点分治】【斜率优化】购票
- BZOJ3672:[Noi2014]购票 (斜率优化DP+二分+(树上CDQ分治/树链剖分))
- [BZOJ3672][NOI2014]购票 树分治斜率优化
- BZOJ3672: [Noi2014]购票 树分治 斜率优化
- bzoj3672 [ NOI2014 ] -- 树上CDQ分治 + 斜率优化DP
- BZOJ 3672 NOI2014 购票 树的点分治+斜率优化
- 树上CDQ分治 NOI2014购票
- 【BZOJ 3672】[Noi2014]购票 树分治+斜率优化
- 【BZOJ 3672】[Noi2014]购票 树分治+斜率优化
- BZOJ 1492 斜率优化dp && cdq分治
- bzoj1492 [ NOI2007 ] --斜率优化DP+cdq分治
- bzoj 3672: [Noi2014]购票 树上cdq分治
- CDQ分治优化DP
- CDQ分治与斜率优化DP——学习笔记
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- [BZOJ1492][NOI2007][CDQ分治][斜率优化][DP]货币兑换Cash
- [BZOJ3963][WF2011]MachineWorks(斜率优化dp+cdq分治)
- 四、4、数组方法
- 八大算法思想(二)------------------递推算法
- py实现网关功能
- think python 课后题实现
- 同步代码块解决线程安全
- [BZOJ3672][NOI2014]购票-点分治-CDQ分治-斜率优化DP
- 802.11协议帧基本格式详解
- ArcGis地图的配准总结
- 【Java】有状态会话bean和无状态会话bean
- 2017年上半年总结:大三下学期,马上大四,马上要毕业了.
- node.js——麻将算法(三)胡牌相关明牌
- 【DevOps】教你一分钟认识DevOps
- bzoj 2038 小Z的袜子 莫队
- 抓取linux向外的tcp连接