从一个点可以走到它的某个祖先处,前提是距离d不超过li,花销为pi*d+qi
求从每个点到达根节点的最小花销
这道题的上一份题解:http://blog.csdn.net/popoqqq/article/details/39009219
很不幸我作死去重写了一发233
之前的写法真是SB的1B。。。 为何要暴力- - 明明是分治结构直接排序不行么- -
简述一下做法:
0.先推出斜率优化的动归方程
1.找到当前分治的树结构的重心
2.将分成的子树中含有根节点那部分连重心一并分治
3.将其余子树的点拎出来,按照能走到的最小深度从大到小排序
4.对于每个点,将重心到根节点路径上所有的点中能到达的那些点维护一个凸包 然后二分查找
5.对其余子树进行分治
时间复杂度O(nlog^2n)
随便写了一发然后RANK6了- - 果然分治要比链剖要快啊233
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 200200 #define INF 1e15 using namespace std; struct abcd{ int to,next; long long f; bool ban; }table[M]; int head[M],tot; int n,type; int fa[M],size[M],points[M]; long long f[M],p[M],q[M],limit[M],dis[M]; namespace Convex_Hull{ struct Point{ long long x,y; Point() {} Point(long long _,long long __): x(_),y(__) {} }stack[M]; int top=M; double slope[M]; double Get_Slope(const Point &p1,const Point &p2) { return (double)(p1.y-p2.y)/(p1.x-p2.x); } void Insert(int x) { Point p=Point(dis[x],f[x]); double s=M-top?Get_Slope(p,stack[top]):INF; while( M-top>=2 && s>=slope[top] ) s=Get_Slope(p,stack[++top]); stack[--top]=p; slope[top]=s; } Point Query(double s) { int temp=lower_bound(slope+top,slope+M,s)-slope; return stack[temp]; } } void Add(int x,int y,long long z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void DFS1(int x) { int i; for(i=head[x];i;i=table[i].next) { dis[table[i].to]=dis[x]+table[i].f; DFS1(table[i].to); } } void Get_Centre_Of_Gravity(int x,int size,int& cg) { int i;bool flag=1; ::size[x]=1; for(i=head[x];i;i=table[i].next) if(!table[i].ban) { Get_Centre_Of_Gravity(table[i].to,size,cg); ::size[x]+=::size[table[i].to]; if(::size[table[i].to]<<1>size) flag=0; } if( (size-::size[x])<<1>size ) flag=0; if(flag) cg=x; } void Get_Points(int x) { int i; points[++points[0]]=x; for(i=head[x];i;i=table[i].next) if(!table[i].ban) Get_Points(table[i].to); } bool Compare(int x,int y) { return dis[x]-limit[x] > dis[y]-limit[y] ; } void Tree_Divide_And_Conquer(int root,int size) { int i,j,cg; if(size==1) return ; Get_Centre_Of_Gravity(root,size,cg); for(i=head[cg];i;i=table[i].next) table[i].ban=1; Tree_Divide_And_Conquer(root,size-::size[cg]+1); points[0]=0; for(i=head[cg];i;i=table[i].next) Get_Points(table[i].to); sort(points+1,points+points[0]+1,Compare); using namespace Convex_Hull; for(i=1,j=cg,top=M;i<=points[0];i++) { int x=points[i]; for(;j!=fa[root]&&dis[j]>=dis[x]-limit[x];j=fa[j]) Insert(j); if(top!=M) { Point p=Query(::p[x]); f[x]=min(f[x],p.y+::p[x]*(dis[x]-p.x)+q[x]); } } for(i=head[cg];i;i=table[i].next) Tree_Divide_And_Conquer(table[i].to,::size[table[i].to]); } int main() { int i; long long length; cin>>n>>type; for(i=2;i<=n;i++) { scanf("%d%lld",&fa[i],&length); scanf("%lld%lld%lld",&p[i],&q[i],&limit[i]); Add(fa[i],i,length); } DFS1(1); memset(f,0x3f,sizeof f);f[1]=0; Tree_Divide_And_Conquer(1,n); for(i=2;i<=n;i++) printf("%lld\n",f[i]); return 0; }
BZOJ 3672 NOI2014 购票 树的点分治+斜率优化
原文地址:http://blog.csdn.net/popoqqq/article/details/42640777