1. 程式人生 > 資訊 >波士頓動力釋出 Spot 機器狗新功能:智慧重新規劃路線

波士頓動力釋出 Spot 機器狗新功能:智慧重新規劃路線

Description

Solution

容易想到一個貪心的思路,記得有個叫什麼國王的遊戲的題,大概就是考慮鄰項作差。如果 \(x\) 在前面比 \(y\) 在前面更優的話,一定有

\[b_{x}(a_y+S)+b_yS > b_y(a_x+S)+b_xS \]

化簡可得

\[b_xa_y > b_ya_x \]

所以最有的情況是按這個排序再依次取。如果擴充套件到樹上的話,就可以用一個堆維護,每次取出最大的。

但是這樣實際上是錯的,因為有依賴關係,即可能有一個點的 \(\frac{b}{a}\) 很小,但它的兒子卻很大。這和藍書上一道染色的題是一個道理。一個性質是,當前所有節點權值最大的點一定會在其父親被選取之後立即被選擇。那麼就可以根據這個倒序更新答案,每次把權值最大的點合併到它的父親,同時計算貢獻。可以用並查集維護。

#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
 
typedef long long ll;
 
inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}
 
const int N=3e5+7;
 
ll a[N],b[N];
int Fa[N],fa[N],sz[N];
 
struct Node{
    int pos,sz; ll x,y;
    Node(int pos_=0,int sz_=0,ll x_=0,ll y_=0):
        pos(pos_),sz(sz_),x(x_),y(y_){}
    bool operator <(const Node &X) const{
        return y*X.x<X.y*x;
    }
};
 
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
 
priority_queue<Node> Q;
 
int main(){
    int n=read(); fa[1]=sz[1]=1;
    for(int i=2;i<=n;i++) Fa[i]=read();
    for(int i=1;i<=n;i++){
        a[i]=read(),b[i]=read();
        if(i!=1) Q.push(Node(i,sz[fa[i]=i]=1,a[i],b[i]));
    }
    ll ans=0;
    while(!Q.empty()){
        Node t=Q.top(); Q.pop(); int u=t.pos;
        if(t.sz!=sz[u]) continue;
        int x=find(Fa[u]),y=find(u);
        if(x==y) continue;
        ans+=a[y]*b[x];
        a[x]+=a[y],b[x]+=b[y];
        sz[x]+=sz[y],fa[y]=x;
        if(x!=1) Q.push(Node(x,sz[x],a[x],b[x]));
    }
    printf("%lld",ans);
}