传送门:uoj198
y,z坐标无用。
先化简一下式子,假设选择的是第 i i 个星球,其 x x 轴上值为 xi x i 。则花费为:
(xi−x0)2+ci=−2xix0+x2i+ci+x20 ( x i − x 0 ) 2 + c i = − 2 x i x 0 + x i 2 + c i + x 0 2
不考虑 x0 x 0 ,这个式子就是个直线,所以我们维护一下凸包就好了。
斜率 K=−2xi K = − 2 x i ,截距 B=x2i+ci B = x i 2 + c i ,按 K K 第一关键字降序, B B 第二关键字升序sort一遍,加入凸包就好了(上凸包)。
鉴于有时间轴的限制,我们来考虑每个操作。
在没有删去操作的前提下:
对于添加一个星球,这条直线会被添加到以该结点为根的子树中的所有结点中。
我们给每个点标两个端点,查询的时候维护一下单调队列。
那么有修改操作时,删除一条直线显然不好做,那么可以知道,在该星球存在的子树中,若某次执行了删除操作,该节点子树内就都没有这条直线了。又可知我们可以把有该直线的结点用dfs序分成一个个区间,我们用线段树对每个区间加一下就好了。
加的时候我们并不需要传递下标,因为这样一条条直线又下传实际上更不好操作,所以直接加在线段树的每个区间节点上,查询的时候直接一层一层推上去,求个min就好了。
我们查询当然是离线下来,按 x x 从小到大线性求凸包。
此题代码细节特别多,注意时空节点和星球标号之间的关系,tag数组我就debug了1h,比如c的范围令人窒息,严格来说斜率 x2i+ci x i 2 + c i 要是数据开满都到 224 2 24 了,还有空间限制,WA,RE了好多次……幸而终于调出来了。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1e6+11;
const int M=5e6+11;
const ll inf=1e17;
int n,m,toa,tob;
int num,st[M],ed[M],pos[N];
int tag[N],cnt,q[N],df[N],ot[N],sz[M];
int ask[N],h[M],dfn;
ll a[N],b[N],ans[N],sit[N];
inline ll rd()
{
char ch=getchar();ll x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
struct L{
int tot,head[N],to[N],nxt[N];
void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
}ori,orz;
inline bool cmp0(const int& x,const int& y)
{return df[x]y];}
inline bool cmp1(const int& x,const int& y)
{return (a[x]==a[y])? b[x]y]:a[x]>a[y];}
inline bool cmp2(const int& x,const int& y)
{return sit[x]y];}
inline bool cal(int x,int y,int z)
{return (a[y]-a[x])*(b[z]-b[x])>=(b[y]-b[x])*(a[z]-a[x]);}
inline ll min(ll x,ll y){return x>y?y:x;}
inline void dfs(int x)
{
df[x]=++dfn;
for(int i=ori.head[x];i;i=ori.nxt[i]) dfs(ori.to[i]);
ot[x]=dfn;
}
inline void ad(int k,int l,int r,int L,int R)
{
if(l>=L && r<=R){sz[k]++;return;}
int mid=(l+r)>>1;
if(L<=mid) ad(k<<1,l,mid,L,R);
if(R>mid) ad(k<<1|1,mid+1,r,L,R);
}
inline void ins(int k,int l,int r,int L,int R,int z)
{
if(l>=L && r<=R){
int &i=ed[k];
while(st[k]1],h[i],z)) i--;
h[++i]=z;
}else{
int mid=(l+r)>>1;
if(L<=mid) ins(k<<1,l,mid,L,R,z);
if(R>mid) ins(k<<1|1,mid+1,r,L,R,z);
}
}
inline void build(int k,int l,int r)
{
st[k]=num+1;ed[k]=num;num+=sz[k];
if(l==r){pos[l]=k;return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline ll get(int k,int x)
{
ll as=inf;
for(k=pos[k];k;k>>=1){
int &i=st[k];
while(i1ll*(a[h[i+1]]-a[h[i]])*x<=b[h[i]]-b[h[i+1]]) i++;
if(i<=ed[k]) as=min(as,1ll*a[h[i]]*x+b[h[i]]);
}
return as;
}
int main(){
scanf("%d%d",&n,&m);b[1]=rd();tag[1]=1;
for(int op,i=2;i<=n;i++){
scanf("%d",&op);
int fr=rd()+1,id=rd()+1;ori.lk(fr,i);
if(op) orz.lk(id,i);else{
tag[id]=i;
a[id]=rd();rd();rd();b[id]=rd();
b[id]+=(ll)a[id]*a[id];a[id]=-(ll)a[id]*2;
}
}
dfs(1);
for(int k,j,i=1;i<=n;i++)if(tag[i]){
for(num=0,j=orz.head[i];j;j=orz.nxt[j]) q[++num]=orz.to[j];
sort(q+1,q+num+1,cmp0);
for(k=df[tag[i]],num=0,j=orz.head[i];j;j=orz.nxt[j]){
orz.to[j]=q[++num];
if(kq[num]]) ad(1,1,n,k,df[q[num]]-1);
k=ot[q[num]]+1;
}
if(k<=ot[tag[i]]) ad(1,1,n,k,ot[tag[i]]);
}
num=0;build(1,1,n);
for(int i=1;i<=n;i++) q[i]=i;
sort(q+1,q+n+1,cmp1);
for(int i,j,k,l=1;l<=n;l++) if(tag[i=q[l]]){
for(k=df[tag[i]],j=orz.head[i];j;j=orz.nxt[j]){
if(k1,1,n,k,df[orz.to[j]]-1,i);
k=ot[orz.to[j]]+1;
}
if(k<=ot[tag[i]]) ins(1,1,n,k,ot[tag[i]],i);
}
for(int tp,i=1;i<=m;i++){
q[i]=i;scanf("%d",&tp);
ask[i]=df[tp+1];sit[i]=rd();
}
sort(q+1,q+m+1,cmp2);
for(int i,l=1;l<=m;l++){i=q[l];ans[i]=get(ask[i],sit[i])+(ll)sit[i]*sit[i];}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}