题目大意:
有一棵n个结点的树,请你搞一些破坏。
直接暴力破坏一个结点i的代价为p[i]。
当然还有非暴力破坏的方法。
每个结点i有一个防御上限c[i],如果与这个点直接相连的点中已经有c[i]个被破坏,那么这个点就会自己坏掉。
一个点坏掉以后要过一秒钟才会带坏周围的点。
如果不考虑时间问题,如何用最小的代价把整棵树搞坏?
思路:
树形DP。
然而这题并没有明显的上下级关系,也就是说父结点和子结点会互相影响。
考虑同时做两个DP,f和g。
f[i]表示先搞坏i子树再搞坏母树的最小代价。
g[i]表示先搞坏母树再搞坏i子树的最小代价。
显然对于一个点,不仅有f和g的情况,还分为手动破坏和自动破坏两种情况。
我们不妨先考虑手动搞坏i点的情况,也就是说,令f[i]=g[i]=p[i]+sum{g[j]|j in son[i]}。
如果要自动搞坏i点,也就是说要把其中c[i]个g[j]替换成对应的f[j],可以对子结点按照f[j]-g[j]排序。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<algorithm> 5 typedef long long int64; 6 const int64 inf=0x7fffffffffffffffll; 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 const int N=50001; 15 std::vector<int> e[N]; 16 inline void add_edge(const int &u,const int &v) { 17 e[u].push_back(v); 18 e[v].push_back(u); 19 } 20 inline void init() { 21 for(register int i=1;i<N;i++) { 22 e[i].clear(); 23 } 24 } 25 int p[N],c[N]; 26 int64 f[N],g[N]; 27 inline bool cmp(const int &x,const int &y) { 28 return f[x]-g[x]<f[y]-g[y]; 29 } 30 void dp(const int &x,const int &par) { 31 f[x]=g[x]=p[x]; 32 int64 sum=0; 33 for(register std::vector<int>::iterator i=e[x].begin();i<e[x].end();i++) { 34 if(*i==par) { 35 e[x].erase(i); 36 break; 37 } 38 } 39 for(unsigned i=0;i<e[x].size();i++) { 40 const int &y=e[x][i]; 41 dp(y,x); 42 sum+=g[y]; 43 } 44 f[x]+=sum; 45 g[x]+=sum; 46 std::sort(e[x].begin(),e[x].end(),cmp); 47 if(c[x]<=(signed)e[x].size()+1) { 48 for(register int i=0;i<c[x]-1;i++) { 49 const int &y=e[x][i]; 50 sum+=f[y]-g[y]; 51 } 52 g[x]=std::min(g[x],sum); 53 if(c[x]<=(signed)e[x].size()) { 54 const int &y=e[x][c[x]-1]; 55 sum+=f[y]-g[y]; 56 f[x]=std::min(f[x],sum); 57 } 58 } 59 } 60 int main() { 61 for(register int T=getint();T;T--) { 62 init(); 63 int n=getint(); 64 for(register int i=1;i<n;i++) { 65 add_edge(getint(),getint()); 66 } 67 for(register int i=1;i<=n;i++) { 68 p[i]=getint(); 69 } 70 for(register int i=1;i<=n;i++) { 71 c[i]=getint(); 72 } 73 dp(1,0); 74 printf("%lld ",f[1]); 75 } 76 return 0; 77 }