一、题目
二、解法
可以看出这些平行时空呈树形结构,每个星球都会出现在一段连续的 d f n dfn dfn序中,而我们正是要对每个时空的星球中找最小值,那么可以把星球打在 d f n dfn dfn的线段树上,使用线段树分治。
考虑怎么从若干个点中选取最优解,首先
y
,
z
y,z
y,z没有卵用,发现是平方的柿子,考虑斜率优化,
x
[
j
]
>
x
[
k
]
x[j]>x[k]
x[j]>x[k]且
j
j
j更优的条件:
(
X
−
x
j
)
2
+
c
j
<
(
X
−
x
k
)
2
+
c
k
(X-x_j)^2+c_j<(X-x_k)^2+c_k
(X−xj)2+cj<(X−xk)2+ck推出来是这个样子:
x
j
2
+
c
j
−
x
k
2
−
c
k
x
j
−
x
k
<
2
X
\frac{x_j^2+c_j-x_k^2-c_k}{x_j-x_k}<2X
xj−xkxj2+cj−xk2−ck<2X画画图可以发现需要维护斜率单调递增的凸包,然后我们先按
x
x
x给每个星球排序,然后就可以插入到线段树里去了,每个点用
v
e
c
t
o
r
vector
vector维护凸包。询问按
x
x
x排序,这样就可以直接弹出对首,每个询问单独处理,从根跑到叶子,每次更新一下最小值即可。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
const int M = 500005;
const ll inf = (1ll<<60);
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,tot,cnt,a[M],dfn[M],to[M],f[M],h[4*M],t[4*M];
ll tmp,ans[M],c[M],val[M];
vector<int> al[M],ar[M],q[4*M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
struct node
{
int x,y,id;
bool operator < (const node &b) const
{
return x<b.x;
}
}p[M];
bool cmp1(int x,int y)
{
return val[x]<val[y];
}
void dfs(int u,int fa)
{
dfn[u]=++cnt;
if(to[u]>0) al[to[u]].push_back(cnt);
if(to[u]<0) ar[-to[u]].push_back(cnt-1);
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
}
if(to[u]>0) ar[to[u]].push_back(cnt);
if(to[u]<0) al[-to[u]].push_back(cnt+1);
}
double kk(int j,int k)
{
return (double)((double)val[j]*val[j]+c[j]-val[k]*val[k]-c[k])/((double)val[j]-val[k]);
}
void ins(int i,int l,int r,int L,int R,int x)
{
if(L>r || l>R) return ;
if(L<=l && r<=R)
{
while(q[i].size()<=t[i]+5) q[i].push_back(0);
while(h[i]<=t[i] && val[q[i][t[i]]]==val[x])
{
if(c[q[i][t[i]]]>=c[x]) t[i]--;
else break;
}
while(h[i]<t[i] && kk(x,q[i][t[i]])<kk(q[i][t[i]],q[i][t[i]-1])) t[i]--;
q[i][++t[i]]=x;
return ;
}
int mid=(l+r)>>1;
ins(i<<1,l,mid,L,R,x);
ins(i<<1|1,mid+1,r,L,R,x);
}
void ask(int i,int l,int r,int pos,ll x)
{
while(h[i]<t[i] && kk(q[i][h[i]+1],q[i][h[i]])<=2.0*x) h[i]++;
if(h[i]<=t[i]) tmp=min(tmp,(x-val[q[i][h[i]]])*(x-val[q[i][h[i]]])+c[q[i][h[i]]]);
if(l==r) return ;
int mid=(l+r)>>1;
if(mid>=pos) ask(i<<1,l,mid,pos,x);
else ask(i<<1|1,mid+1,r,pos,x);
}
signed main()
{
n=read();m=read();scanf("%lld",&c[0]);
for(int i=1;i<n;i++)
{
int op=read();
if(op==0)
{
int u=read(),x=read();
to[i]=x;
scanf("%lld",&val[x]);read();read();scanf("%lld",&c[x]);
e[++tot]=edge(i,f[u]),f[u]=tot;
e[++tot]=edge(u,f[i]),f[i]=tot;
}
else
{
int u=read(),x=read();
to[i]=-x;
e[++tot]=edge(i,f[u]),f[u]=tot;
e[++tot]=edge(u,f[i]),f[i]=tot;
}
}
dfs(0,0);
for(int i=1;i<=4*n;i++) h[i]=0,t[i]=-1;
for(int i=1;i<=n;i++) a[i]=i;
ins(1,1,n,1,n,0);
sort(a+1,a+1+n,cmp1);
for(int i=1;i<=n;i++)
{
int x=a[i];
for(int j=0;j<al[x].size();j++)
{
int LL=al[x][j],RR=ar[x][j];
ins(1,1,n,LL,RR,x);
}
}
for(int i=1;i<=m;i++)
{
int y=read(),x=read();
p[i]=node{x,y,i};
}
sort(p+1,p+1+m);
for(int i=1;i<=m;i++)
{
tmp=inf;
ask(1,1,n,dfn[p[i].y],p[i].x);
ans[p[i].id]=tmp;
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
}