BZOJ 4557 侦察守卫

DP

\(F_{i,j}\) 表示处理掉以 \(i\) 为根的子树,并向上支援 \(j\) 格的最小代价

\(j\in [-D,D]\)

暴力转移 \(O(ND^3)\) ~ \(O(ND^2)\)

稍作修改

\(F_{i,j}\) 表示处理掉以 \(i\) 为根的子树,并向上支援至少 \(j\) 格的最小代价

容易得到 \(O(ND)\) 做法

#include <cstdio>
#include <vector>
#include <algorithm>

using std::min;
using std::vector;

const int MAXN=500111;
const int MAXD=23;
const int INF=1034567890;

int N, D, M;

struct Vert{
    int Val;
    bool Is;
    int FE;
    int F_[MAXD<<1], *F;
    Vert(){F=F_+MAXD;}
} V[MAXN];

struct Edge{
    int y, next;
} E[MAXN<<1];

int Ecnt;

void addE(int a, int b){
    ++Ecnt;
    E[Ecnt].y=b;E[Ecnt].next=V[a].FE;V[a].FE=Ecnt;
}

void DFS(int at, int f){
    vector<int> Son;
    for(int k=V[at].FE, to;k;k=E[k].next){
        to=E[k].y;
        if(to==f)   continue;
        Son.push_back(to);
        DFS(to, at);
    }
    if(!Son.size()){
        for(int i=1-V[at].Is;i<=D;++i)  V[at].F[i]=V[at].Val;
        return;
    }
    //j=D;
    for(int i=0, s=Son.size();i<s;++i){
        V[at].F[D]+=V[Son[i]].F[-D];
    }
    V[at].F[D]+=V[at].Val;
    //j=[1,D);
    for(int j=!V[at].Is, t;j<D;++j){
        t=0;
        for(int i=0, s=Son.size();i<s;++i){
            t+=V[Son[i]].F[-j];
        }
        V[at].F[j]=V[Son[0]].F[j+1]-V[Son[0]].F[-j]+t;
        for(int i=1, s=Son.size();i<s;++i){
            V[at].F[j]=min(V[at].F[j], V[Son[i]].F[j+1]-V[Son[i]].F[-j]+t);
        }
    }
    //j=0;
    if(!V[at].Is)
        for(int i=0, s=Son.size();i<s;++i)
            V[at].F[0]+=V[Son[i]].F[0];
    //j=-1;
    if(!V[at].Is)   V[at].F[-1]=INF;
    //j=[-D,-1);
    for(int j=-2+V[at].Is;j>=-D;--j){
        for(int i=0, s=Son.size();i<s;++i)
            V[at].F[j]+=V[Son[i]].F[j+1];
    }
    for(int i=D-1;i>=-D;--i)    V[at].F[i]=min(V[at].F[i+1], V[at].F[i]);
}

int main(){
    
    scanf("%d%d", &N, &D);
    
    for(int i=1;i<=N;++i)   scanf("%d", &V[i].Val);
    
    scanf("%d", &M);
    
    for(int i=1, a;i<=M;++i)    {scanf("%d", &a);V[a].Is=true;}
    
    for(int i=1, a, b;i<N;++i){
        scanf("%d%d", &a, &b);
        addE(a, b);addE(b, a);
    }
    
    DFS(1, 0);
    
    printf("%d\n", V[1].F[0]);
    
    return 0;
}

/*
12 2
8 9 12 6 1 1 5 1 4 8 10 6
10
1 2 3 5 6 7 8 9 10 11
1 3
2 3
3 4
4 5
4 6
4 7
7 8
8 9
9 10
10 11
11 12

10

*/

猜你喜欢

转载自www.cnblogs.com/Pickupwin/p/BZOJ4557.html