[CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities

題目大意:
  有一棵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 }
相關文章
相關標籤/搜索