bzoj3672 [Noi2014]购票
推一下式子发现就是普通的斜率优化,但是放到了树上,那么我们怎么做呢,树上有什么能保证复杂度的求路径的算法呢,点分治!
但是这是有根树,我们对于首先处理点分治后的重心以及与根相连的那个块,之后我们将块中剩余的点按照向上扩展的最大深度排序,深度由大到小插入凸包,注意这里添加的点一定是在块内的,否则复杂度就错了。之后我们再处理其他的块。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 #define N 205000 8 #define inf 0x7fffffffffffffff 9 #define int long long 10 using namespace std; 11 int MAX(int a,int b){return a>b?a:b;} 12 struct point{ 13 int x[2]; 14 point(){} 15 point(int a,int b){x[0]=a,x[1]=b;} 16 }; 17 vector <point> v; 18 double slope(point a,point b) 19 {return (double)(a.x[1]-b.x[1])/1.0/(a.x[0]-b.x[0]);} 20 int fa[N],size[N],maxn[N],s[N],p[N],q[N],l[N]; 21 int f[N],dep[N]; 22 int root,sum,vis[N<<1],lk[N]; 23 int e=2,head[N]; 24 struct edge{ 25 int u,v,w,next; 26 }ed[N<<1]; 27 void add(int u,int v,int w){ 28 ed[e].u=u;ed[e].v=v;ed[e].w=w; 29 ed[e].next=head[u];head[u]=e++; 30 } 31 void insert(int x){ 32 int sz=v.size(); 33 point P=point(dep[x],f[x]); 34 while(sz>1&&slope(v[sz-2],v[sz-1])<=slope(v[sz-1],P))sz--,v.pop_back(); 35 v.push_back(P); 36 } 37 int query(int x){ 38 int l=1,r=v.size()-1,mid,ans=0; 39 point P=point(1,p[x]); 40 while(l<=r){ 41 mid=(l+r)>>1; 42 if(slope(v[mid],v[mid-1])>=p[x])ans=mid,l=mid+1; 43 else r=mid-1; 44 } 45 return v[ans].x[1]+(dep[x]-v[ans].x[0])*p[x]+q[x]; 46 } 47 void dfs(int x){ 48 for(int i=head[x];i;i=ed[i].next){ 49 int v=ed[i].v; 50 if(v==fa[x])continue; 51 dep[v]=dep[x]+ed[i].w; 52 dfs(v); 53 } 54 } 55 void getroot(int rt,int x){ 56 size[x]=1;maxn[x]=0; 57 for(int i=head[x];i;i=ed[i].next){ 58 int v=ed[i].v; 59 if(vis[i])continue; 60 getroot(rt,v); 61 size[x]+=size[v]; 62 maxn[x]=MAX(maxn[x],size[v]); 63 } 64 maxn[x]=MAX(maxn[x],sum-size[x]); 65 if(maxn[x]<maxn[root]||(maxn[x]==maxn[root]&&dep[x]<dep[root]))/*puts("??"),*/root=x; 66 } 67 int a[N],tot; 68 void dfs1(int x){ 69 a[++tot]=x; 70 for(int i=head[x];i;i=ed[i].next){ 71 int v=ed[i].v; 72 if(vis[i])continue; 73 dfs1(v); 74 } 75 } 76 bool cmp(int a,int b) 77 {return dep[a]-l[a]>dep[b]-l[b];} 78 void work(int rt,int x){ 79 if(sum==1)return ; 80 for(int i=head[x];i;i=ed[i].next){ 81 int v=ed[i].v; 82 vis[i]=1; 83 } 84 int all=sum,sx=size[x]; 85 if(fa[x]&&!vis[lk[x]]){ 86 sum=size[fa[x]]>sx?all-sx+1:size[fa[x]]+1; 87 root=0;getroot(rt,rt);work(rt,root); 88 } 89 tot=0; 90 for(int i=head[x];i;i=ed[i].next){ 91 int v=ed[i].v; 92 dfs1(v); 93 } 94 sort(a+1,a+tot+1,cmp); 95 v.clear(); 96 for(int i=1,j=x;i<=tot;i++){ 97 int now=a[i]; 98 for(;j!=fa[rt]&&dep[j]>=dep[now]-l[now];j=fa[j])insert(j); 99 if(v.size())f[now]=min(f[now],query(now)); 100 } 101 for(int i=head[x];i;i=ed[i].next){ 102 int v=ed[i].v; 103 root=0;sum=size[v]>sx?all-sx:size[v]; 104 getroot(v,v);work(v,root); 105 } 106 } 107 int n,opt; 108 signed main(){ 109 memset(f,0x3f,sizeof f); 110 f[1]=0; 111 scanf("%lld%lld",&n,&opt); 112 for(int i=2;i<=n;i++){ 113 scanf("%lld%lld%lld%lld%lld",&fa[i],&s[i],&p[i],&q[i],&l[i]); 114 add(fa[i],i,s[i]);lk[i]=e-1; 115 } 116 dfs(1); 117 root=0;sum=n;maxn[0]=n+1; 118 getroot(1,1); 119 work(1,root); 120 for(int i=2;i<=n;i++)printf("%lld\n",f[i]); 121 return 0; 122 }
人生如梦亦如幻 朝如晨露暮如霞。