題目大意:
有一棵n個結點的樹,請你搞一些破壞。
直接暴力破壞一個結點i的代價爲p[i]。
固然還有非暴力破壞的方法。
每一個結點i有一個防護上限c[i],若是與這個點直接相連的點中已經有c[i]個被破壞,那麼這個點就會本身壞掉。
一個點壞掉之後要過一秒鐘纔會帶壞周圍的點。
若是不考慮時間問題,如何用最小的代價把整棵樹搞壞?
git
思路:
樹形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]排序。spa
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\n",f[1]); 75 } 76 return 0; 77 }