每次查询按照剖分查就可以了,复杂度O(log^3n)
注意,本题算叉积的时候会爆longlong,要转成double
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #include<vector> #define maxn 200010 #define inf 1e18 using namespace std; struct yts { long long x,y; }p[maxn],tmp[maxn]; bool operator<(yts x,yts y) { return x.x<y.x || (x.x==y.x && x.y<y.y); } double operator*(yts x,yts y) { double X1=x.x,X2=y.x,Y1=x.y,Y2=y.y; return X1*Y2-X2*Y1; } yts operator-(yts x,yts y) { yts ans; ans.x=x.x-y.x;ans.y=x.y-y.y; return ans; } struct yts1 { int l,r; int size; bool flag; vector<yts> v; }t[4*maxn]; int st[maxn],to[maxn],next[maxn],fa[maxn],pre[maxn],g[20][maxn]; long long len[maxn],dep[maxn],f[maxn]; int seq[maxn],head[maxn],e[maxn],rank[maxn],size[maxn],dd[maxn],d[maxn]; long long P[maxn],Q[maxn],L[maxn]; bool vis[maxn]; int n,m,num,tot,T; void addedge(int x,int y,long long z) { num++;to[num]=y;len[num]=z;next[num]=st[x];st[x]=num; } void dfs1(int x) { e[++tot]=x;dd[x]=0;size[x]=1; for (int p=st[x];p;p=next[p]) { dep[to[p]]=dep[x]+len[p];d[to[p]]=d[x]+1; dfs1(to[p]); size[x]+=size[to[p]]; if (size[to[p]]>size[dd[x]]) dd[x]=to[p]; } } int cal(int x) { int ans=x; for (int k=19;k>=0;k--) if (g[k][ans] && dep[x]-dep[g[k][ans]]<=L[x]) ans=g[k][ans]; return ans; } void build(int i,int l,int r) { t[i].l=l;t[i].r=r;t[i].flag=0; yts x;x.x=0;x.y=0; for (int j=t[i].l;j<=t[i].r+1;j++) t[i].v.push_back(x); if (l==r) return; int mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); } void build(int i) { int size=0; for (int j=t[i].l;j<=t[i].r;j++) tmp[++size]=p[j]; sort(tmp+1,tmp+size+1); t[i].size=0; for (int j=1;j<=size;j++) { while (t[i].size>1 && (tmp[j]-t[i].v[t[i].size])*(t[i].v[t[i].size]-t[i].v[t[i].size-1])>=0) t[i].size--; t[i].v[++t[i].size]=tmp[j]; } } long long calc(int i,int j,int id) { return t[i].v[j].y+(dep[id]-t[i].v[j].x)*P[id]+Q[id]; } long long query(int i,int id) { long long ans=inf; int l=1,r=t[i].size; while (r-l>=3) { int mid=l+(r-l)/3,midmid=r-(r-l)/3; if (calc(i,mid,id)<calc(i,midmid,id)) r=midmid; else l=mid; } for (int j=l;j<=r;j++) ans=min(ans,calc(i,j,id)); return ans; } long long query(int i,int l,int r,int id) { if (l<=t[i].l && t[i].r<=r) { if (!t[i].flag) build(i),t[i].flag=1; return query(i,id); } int mid=(t[i].l+t[i].r)/2; long long ans=inf; if (l<=mid) ans=min(ans,query(i*2,l,r,id)); if (mid<r) ans=min(ans,query(i*2+1,l,r,id)); return ans; } long long query(int x,int y,int id) { long long ans=inf; while (d[head[x]]>d[y]) { ans=min(ans,query(1,rank[head[x]],rank[x],id));x=fa[head[x]]; } ans=min(ans,query(1,rank[y],rank[x],id)); return ans; } int main() { scanf("%d%d",&n,&T); for (int i=2;i<=n;i++) { int x; scanf("%d%lld%lld%lld%lld",&fa[i],&x,&P[i],&Q[i],&L[i]); addedge(fa[i],i,x); } dfs1(1); int qwer=0; for (int i=1;i<=n;i++) if (!vis[e[i]]) { int k=e[i]; while (k) { seq[++qwer]=k;head[k]=e[i];vis[k]=1;k=dd[k]; } } for (int i=1;i<=n;i++) rank[seq[i]]=i,g[0][i]=fa[i]; for (int j=1;j<=18;j++) for (int i=1;i<=n;i++) g[j][i]=g[j-1][g[j-1][i]]; for (int i=1;i<=n;i++) pre[i]=cal(i); build(1,1,n); f[1]=0;dep[1]=0;p[rank[1]].x=0;p[rank[1]].y=0; for (int i=2;i<=n;i++) { f[i]=query(fa[i],pre[i],i); p[rank[i]].x=dep[i];p[rank[i]].y=f[i]; printf("%lld\n",f[i]); } return 0; }