标签:区间 using tin code targe c++ bool pre lse
题解
考虑啥限制都没有的话,也就是在一个序列上且没有 $l$ 的限制,那就是 $dp$ 然后斜率优化
$f_i$ 表示 $i$ 的答案, $f_i=min(f_j+(d_i-d_j)p_i+q_i)$ ,其中 $d_i$ 表示 $s$ 的前缀和,可以化成斜率优化的式子
由于斜率不递增所以在凸包上二分即可
考虑 $l$ 的限制的话,那我们可以做类似 $cdq$ 的东西,也就是考虑 $[l,mid]$ 对 $[mid+1,r]$ 的影响,那可以对右区间以最前能取到的点从大到小排序,然后双指针加入凸包即可
考虑在一棵树上的话,那我们考虑点分治,即对于树 $u$ 求出了重心 $rt$ ,考虑 $(u,rt)$ 路径上的点对 $rt$ 子树的影响,那我们可以先除去 $rt$ 子树内的点(除了 $rt$ ),然后递归求出剩下点的 $dp$ 值,然后我们可以像刚刚的操作即把 $rt$ 子树内除了 $rt$ 的点按照最高能取到的点按深度从大到小排序,然后双指针加入凸包即可
效率: $O(nlog^2n)$
代码
#include <bits/stdc++.h> #define LL long long #define db long double using namespace std; const int N=2e5+5; int n,fa[N],o,rt,sz[N],son[N],a[N],hd[N],V[N],nx[N],t,S[N],tp; LL d[N],s[N],p[N],q[N],g[N],f[N];bool vis[N]; bool cmp(int A,int B){ return d[A]-g[A]>d[B]-g[B]; } void add(int u,int v){ nx[++t]=hd[u];V[hd[u]=t]=v; } db K(int x,int y){ return ((db)f[y]-f[x])/((db)d[y]-d[x]); } void Dis(int x){ for (int i=hd[x];i;i=nx[i]) d[V[i]]=d[x]+s[V[i]],Dis(V[i]); } void Sz(int x){ sz[x]=1; for (int i=hd[x],v;i;i=nx[i]) if (!vis[v=V[i]]) Sz(v),sz[x]+=sz[v]; } void Rt(int x){ son[x]=o-sz[x]; for (int i=hd[x],v;i;i=nx[i]) if (!vis[v=V[i]]) Rt(v),son[x]=max(son[x],sz[v]); if (son[x]<=son[rt]) rt=x; } void find(int x){ a[++t]=x; for (int i=hd[x];i;i=nx[i]) if (!vis[V[i]]) find(V[i]); } void work(int x){ Sz(x);o=sz[x];rt=0;Rt(x); if (o==1){vis[x]=1;return;} for (int i=hd[rt];i;i=nx[i]) vis[V[i]]=1; int u=rt;work(x);tp=t=0; for (int i=hd[u];i;i=nx[i]) vis[V[i]]=0,find(V[i]); sort(a+1,a+t+1,cmp);int X=x;x=u; for (int i=1,v,l,r,j;i<=t;i++){ v=a[i]; while(d[u]>=d[X] && d[u]>=d[v]-g[v]){ while(tp>1 && K(S[tp-1],u)>=K(S[tp-1],S[tp])) tp--; S[++tp]=u;u=fa[u]; } if (!tp) continue;l=1;r=tp; while(l<r){ j=(l+r+1)>>1; if (K(S[j],S[j-1])>=p[v]) l=j; else r=j-1; } f[v]=min(f[v],f[S[l]]+(d[v]-d[S[l]])*p[v]+q[v]); } vis[x]=1; for (int i=hd[x];i;i=nx[i]) work(V[i]); } int main(){ cin>>n>>tp;son[0]=1e9;d[0]=-1; for (int i=2;i<=n;i++) scanf("%d%lld%lld%lld%lld", &fa[i],&s[i],&p[i],&q[i],&g[i]), f[i]=2e18,add(fa[i],i); Dis(1);work(1); for (int i=2;i<=n;i++) printf("%lld\n",f[i]); return 0; }
标签:区间 using tin code targe c++ bool pre lse
原文地址:https://www.cnblogs.com/xjqxjq/p/12288854.html