21.6.13 t3

tag:树形dp


\(n^3\) 暴力,设 \(f_{i,j}\) 表示 \(i\) 的关键点为 \(j\)

转移时枚举 \(x\) 的关键点和 \(son\) 的关键点,转移条件即为满足关键点的性质(关键点为所有源点中离它最近的)

  • \(dis(x,p_x)\le dis(x,p_{son})\)
  • \(dis(son,p_{son})\le dis(son,p_{son})\)

然后如果按 \(dis_x\) 从大到小排序,就变成了一个单点修改,求前缀 \(min\) 的问题(对于按 \(dis_{son}\) 从小到大的排列来说)

复杂度 \(O(n^2logn)\),可以用BIT。


#include<bits/stdc++.h>
using namespace std;

template<typename T>
inline void Read(T &n){
	char ch; bool flag=false;
	while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
	for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
	if(flag)n=-n;
}

enum{
    MAXN = 1005
};

int f[MAXN][MAXN], n, t[MAXN], a[MAXN];

struct _{
    int nxt, to;
    _(int nxt=0, int to=0):nxt(nxt),to(to){}
}edge[MAXN<<1];
int fst[MAXN], tot;

inline void Add_Edge(int f, int t){
    edge[++tot] = _(fst[f], t); fst[f] = tot;
    edge[++tot] = _(fst[t], f); fst[t] = tot;
}

int dis[MAXN][MAXN], rt;
void getdis(int x, int y){
    for(register int u=fst[x]; u; u=edge[u].nxt){
        int v=edge[u].to;
        if(v==y) continue;
        dis[rt][v] = dis[rt][x]+1;
        getdis(v,x);
    }
}

namespace BIT{
    #define lowbit(x) (x&-x)
    int t[MAXN];
    inline void Add(int x, int k){for(;x<=n;x+=lowbit(x))t[x]=min(t[x],k);}
    inline int Query(int x){int res=INT_MAX;for(;x;x-=lowbit(x))res=min(res,t[x]);return res;}
    #undef lowbit
}
using BIT::Add;
using BIT::Query;

int p[MAXN][MAXN], now, loc[MAXN][MAXN], mxr[MAXN][MAXN];
inline bool cmp(const int &u, const int &v){
    return dis[now][u]<dis[now][v];
}

void dp(int x, int y){
    for(register int i=1; i<=n; i++) f[x][i] = t[dis[x][i]]; f[x][x] = a[x];
    for(register int u=fst[x]; u; u=edge[u].nxt){
        int v=edge[u].to;
        if(v==y) continue;
        dp(v,x);

        // for(register int i=1; i<=n; i++){
        //     int res=INT_MAX;
        //     for(register int j=1; j<=n; j++)
        //         if(dis[x][j]>=dis[x][i] and dis[v][i]>=dis[v][j])
        //             res = min(res,f[v][j]);
        //     f[x][i] += res;
        //     printf("(%d %d %d) %d\n",x,i,v,res);
        // }

        for(register int i=1; i<=n; i++) BIT::t[i] = INT_MAX;
        for(register int r=n, l; r; r=l-1){
            l=r; while(l>1 and dis[x][p[x][l]]==dis[x][p[x][l-1]]) Add(loc[v][p[x][l]],f[v][p[x][l]]), l--;
            Add(loc[v][p[x][l]],f[v][p[x][l]]);
            for(register int j=l; j<=r; j++) f[x][p[x][j]] += Query(mxr[v][dis[v][p[x][j]]]);
        }
    }
}

int main(){
    // freopen("3.in","r",stdin);
    // freopen("33.out","w",stdout);
    Read(n);
    for(register int i=1; i<=n; i++) Read(a[i]);
    for(register int i=1; i<=n; i++) Read(t[i]);
    for(register int i=1; i<n; i++){
        int u, v;
        Read(u); Read(v);
        Add_Edge(u,v);
    }
    for(rt=1; rt<=n; rt++) getdis(rt,0);
    for(register int i=1; i<=n; i++){
        for(register int j=1; j<=n; j++) p[i][j] = j;
        now = i; sort(p[i]+1,p[i]+n+1,cmp);
        for(register int j=1; j<=n; j++) loc[i][p[i][j]] = j, mxr[i][dis[i][p[i][j]]] = j;
    }
    dp(1,0);
    int ans=INT_MAX;
    for(register int i=1; i<=n; i++) ans = min(ans,f[1][i]);
    cout<<ans<<'\n';
    return 0;
}
posted @ 2021-06-24 20:22  oisdoaiu  阅读(25)  评论(0编辑  收藏  举报