• BZOJ 4557 侦察守卫


    DP

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

    (jin [-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
    ", 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
    
    */
    
    
  • 相关阅读:
    windows下安装redis
    十五oracle 触发器
    Flask 学习 六 大型程序结构
    Flask 学习 五 电子邮件
    Flask 学习 四 数据库
    Flask学习 三 web表单
    Flask学习 二 模板
    Flask学习 一 基本结构
    Python操作Redis
    Python操作MySQL
  • 原文地址:https://www.cnblogs.com/Pickupwin/p/BZOJ4557.html
Copyright © 2020-2023  润新知