UOJ#7. 【NOI2014】购票 点分治 斜率优化 凸包 二分
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ7.html
题解
这题是Unknown的弱化版。
如果这个问题出在序列上,那么显然可以CDQ分治 + 斜率优化 + 凸包上二分来做。
那么它出在树上?
点分治。
写挂了好多地方调了好久,自闭了。
代码
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\ For(_v2,L,R)printf("%d ",a[_v2]);puts(""); using namespace std; typedef long long LL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=200005; const LL INF=1e18; int n,type; vector <int> e[N]; int fa[N]; LL d[N],p[N],q[N],lim[N]; LL dp[N]; int size[N],mx[N]; int RT,Size; int vis[N]; void get_root(int x,int pre){ size[x]=1,mx[x]=0; for (auto y : e[x]) if (y!=pre&&!vis[y]){ get_root(y,x); size[x]+=size[y]; mx[x]=max(mx[x],size[y]); } mx[x]=max(mx[x],Size-size[x]); if (!RT||mx[x]<mx[RT]) RT=x; } struct Point{ LL x,y; Point(){} Point(LL _x,LL _y){ x=_x,y=_y; } }a[N]; int top; vector <int> id; LL Ask(LL p,LL lim){ if (!top) return INF; int L=1,R=top-1,mid; LL ans=a[top].y-a[top].x*p; while (L<=R){ mid=(L+R)>>1; if (p*(a[mid].x-a[mid+1].x)>=a[mid].y-a[mid+1].y) R=mid-1,ans=min(ans,a[mid].y-a[mid].x*p); else L=mid+1; } return ans; } bool cross(Point a,Point b,Point c){ return (__int128)(b.x-a.x)*(c.y-a.y)-(__int128)(c.x-a.x)*(b.y-a.y)<0; } void Ins(Point p){ while (top>1&&!cross(a[top-1],a[top],p)) top--; a[++top]=p; } void upd_dp(int x){ dp[x]=min(dp[x],Ask(p[x],lim[x])+q[x]+p[x]*d[x]); } vector <int> s; void Get(int x,int pre){ s.pb(x); for (auto y : e[x]) if (y!=pre&&!vis[y]) Get(y,x); } bool cmp(int a,int b){ return lim[a]>lim[b]; } void solve(int x){ RT=0,get_root(x,0),x=RT; vector <int> id; id.clear(); for (int i=x;!vis[i];i=fa[i]) id.pb(i); vis[x]=1; int sp=Size-size[x]; if (!vis[fa[x]]){ Size=size[fa[x]]>size[x]?sp:size[fa[x]]; solve(fa[x]); } for (auto y : id) if (y!=x&&d[y]>=lim[x]) dp[x]=min(dp[x],dp[y]+p[x]*(d[x]-d[y])+q[x]); s.clear(); for (auto y : e[x]) if (!vis[y]&&y!=fa[x]) Get(y,x); sort(s.begin(),s.end(),cmp); int i=0; top=0; for (auto x : id){ while (i<s.size()&&lim[s[i]]>d[x]) upd_dp(s[i++]); Ins(Point(d[x],dp[x])); } while (i<s.size()) upd_dp(s[i++]); for (auto y : e[x]) if (!vis[y]&&y!=fa[x]){ Size=size[y]>size[x]?sp:size[y]; solve(y); } } int main(){ n=read(),type=read(); For(i,2,n){ fa[i]=read(); d[i]=read()+d[fa[i]]; p[i]=read(); q[i]=read(); lim[i]=d[i]-read(); e[i].pb(fa[i]),e[fa[i]].pb(i); dp[i]=INF; } vis[0]=1,Size=n; solve(1); For(i,2,n) printf("%lld\n",dp[i]); return 0; }