Description
2045年,人类的技术突飞猛进,已经找到了进行时空旅行的方法。小R得到了一台时空旅行仪,他想用它调查不同
时空中人类的发展状况。根据平行时空理论,宇宙中存在着很多独立的时空,每个时空在下一个时间点还会分化出
若干个不同的时空。宇宙是一个三维空间,人类使用空间直角坐标系来描述空间中的一个位置,三维坐标分别是 x
,y,z。我们假设在初始的时空(编号为 0)中,人类存在于地球上(地球的坐标为 (0,0,0)),其它的时空都是从
一个现有的时空发展而来。一个时空发生一个事件之后会发展成为另外一个时空(原来的时空不发生任何变化)。
会影响小R的事件包括两类:人类殖民了一个新的星球,该星球的状态变成”已被殖民”;人类放弃了一个已被殖民
的星球,该星球的状态变成”未被殖民”。每次进行时空旅行时,小R会先选定一个时空。在这个时空中,人类已经
殖民了一些星球。小R只要到达该时空中任意一个已被殖民的星球,就能调查人类的发展状况。小R的时空旅行仪出
现了一些问题,调整 x 坐标的按钮坏掉了,因此到达点的 x 坐标被固定了(每次旅行的 x 坐标值可能不同)。
与此同时,他仍能任意调整到达点的 y 坐标和 z 坐标。这个问题大大增大了小R的花费:因为时空旅行没有花费
,但在太空中航行却需要花钱;同时,在不同的星球进行调查也可能会产生不同的费用。假设小R将时空旅行的终
点设为 A,他要进行调查的星球为 B:如果 A 与 B 的欧几里德距离为 d,那么他太空航行的花费就为 d^2;又如
果星球 B 上进行调查的费用为 c,那么小R此次调查的总花费就为 d^2+c。现在给定小R每次旅行到达的时空以及
时空旅行仪上固定的 x 坐标值,请你计算出小R每次旅行完成调查的最小总花费。
Input
输入的第一行包含三个非负整数 n,m,c_0,
n 表示平行时空数量,这些平行时空的编号为 0 到 n-1 的整数,初始时空的编号为 0。
m 表示小R进行的时空旅行的次数,
c_0 表示在地球进行调查的花费。保证 n,m 是正整数,0≤c_0≤10^12。
接下来 n-1 行,依次描述平行时空 1 到 n-1,其中第 i 行分两种情况:
0 fr id x y z c:表示编号为 i 的平行时空由编号为 fr 的时空发展而来,数据保证人类殖民了一个编号为 id 的星球,
该星球的坐标为 (x,y,z),在该星球进行调查的花费为 c。
数据保证给出的星球编号不重复,且 0
Output
输出 m 行,分别表示每次旅行完成调查的最小总花费。
Sample Input
4 4 2
0 0 1 8 2 3 7
0 1 2 10 1 6 2
1 1 1
1 4
2 8
2 6
3 8
Sample Output
18
6
11
66
解题思路:
y y 和 都是没用的,就是求
相当于一个点是一条直线,求 x0=x x 0 = x 时的最小值。
注意有删除操作,肯定要转成插入,注意至多把dfs分成 O(n) O ( n ) 段,还是可以用线段树去维护区间内的凸包,标记永久化,单点查询即可。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
ll getint()
{
ll i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=500005;
int n,m,cnt,id[N],p[N];
int tot,first[N],nxt[N],to[N];
int idx,in[N],out[N];
vector<int>inc[N],del[N];
struct line
{
ll k,b;int id;
line(ll _k=0,ll _b=0,int _id=0):k(_k),b(_b),id(_id){}
inline friend line operator - (const line &a,const line &b){return line(a.k-b.k,a.b-b.b);}
inline friend bool operator < (const line &a,const line &b){return a.k>b.k;}
inline friend double operator * (const line &a,const line &b){return (double)a.k*b.b-(double)a.b*b.k;}
inline ll calc(int x){return k*x+b;}
}L[N];
struct data
{
int u,x,id;
inline friend bool operator < (const data &a,const data &b){return a.x<b.x;}
}q[N];
struct node
{
vector<line>a;int pos,top;
node(){pos=0,top=-1;}
void insert(line t)
{
if(top>=0&&t.k==a[top].k)
{
if(t.b>=a[top].b)return;
else top--,a.pop_back();
}
while(top>=1&&(a[top]-a[top-1])*(t-a[top-1])>=0)
top--,a.pop_back();
top++,a.push_back(t);
}
ll calc(int x0)
{
if(top==-1)return 1e18;
while(pos<top&&a[pos].calc(x0)>=a[pos+1].calc(x0))pos++;
return a[pos].calc(x0);
}
}tr[N<<2];
ll ans[N];
void add(int x,int y)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void dfs(int u)
{
in[u]=++idx;
id[u]>0?inc[id[u]].pb(idx):del[-id[u]].pb(idx);
for(int e=first[u];e;e=nxt[e])dfs(to[e]);
out[u]=idx;
id[u]>0?del[id[u]].pb(idx+1):inc[-id[u]].pb(idx+1);
}
void modify(int k,int l,int r,int x,int y,line t)
{
if(x<=l&&r<=y){tr[k].insert(t);return;}
int mid=l+r>>1;
if(x<=mid)modify(k<<1,l,mid,x,y,t);
if(y>mid) modify(k<<1|1,mid+1,r,x,y,t);
}
ll query(int k,int l,int r,int x,int x0)
{
ll res=tr[k].calc(x0);
if(l==r)return res;
int mid=l+r>>1;
if(x<=mid)return min(res,query(k<<1,l,mid,x,x0));
else return min(res,query(k<<1|1,mid+1,r,x,x0));
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
n=getint(),m=getint(),L[++cnt]=line(0ll,getint(),1),id[1]=1;
for(int i=2,op,x;i<=n;i++)
{
op=getint(),add(getint()+1,i);
if(op==1)id[i]=-getint()-1;
else
{
id[i]=getint()+1;
x=getint(),getint(),getint();
L[++cnt]=line(-2ll*x,getint()+(ll)x*x,id[i]);
}
}
sort(L+1,L+cnt+1);for(int i=1;i<=cnt;i++)p[L[i].id]=i;
for(int i=1;i<=n;i++)id[i]=id[i]>0?p[id[i]]:-p[-id[i]];
dfs(1);
for(int i=1;i<=cnt;i++)
for(int j=inc[i].size()-1,l,r;j>=0;j--)
{
l=inc[i][j],r=del[i][j]-1;
if(l<=r)modify(1,1,n,l,r,L[i]);
}
for(int i=1;i<=m;i++)q[i].u=getint()+1,q[i].x=getint(),q[i].id=i;
sort(q+1,q+m+1);
for(int i=1;i<=m;i++)ans[q[i].id]=query(1,1,n,in[q[i].u],q[i].x)+(ll)q[i].x*q[i].x;
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
return 0;
}