[POI2014]FarmCraft

题目大意:
  一个$n(n\le5\times10^5)$个点的树,每个点有一个权值$c_i$,从$1$出发进行欧拉遍历,每个单位时间移动一条边,记每个点$i$被访问到的时间是$t_i$,问最后$\max\{t_i+c_i\}$的最小值(点$1$算作最后访问)。

思路:
  $f[i]$表示欧拉遍历以$i$为根的子树的时间,$g[i]$表示对于以点$i$为根的子树中,对于每个点$j$,$\max\{t_j+c_j\}-t_i$的最小值。
  转移时考虑贪心,对于子结点$j$,$g[j]-f[j]$的值可以在遍历别的子树的过程中抵消掉,因此可以将子结点关于$g[j]-f[j]$降序排序并进行转移。最后答案即为$\max(g[1],f[1]+c_1)$。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 #include<algorithm>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=500001;
13 int c[N],f[N],g[N];
14 std::vector<int> e[N];
15 inline void add_edge(const int &u,const int &v) {
16     e[u].push_back(v);
17     e[v].push_back(u);
18 }
19 inline bool cmp(const int &a,const int &b) {
20     return g[a]-f[a]>g[b]-f[b];
21 }
22 void dfs(const int &x,const int &par) {
23     for(unsigned i=0;i<e[x].size();i++) {
24         const int &y=e[x][i];
25         if(y==par) continue;
26         dfs(y,x);
27         g[y]=std::max(g[y]+1,f[y]+=2);
28     }
29     std::sort(e[x].begin(),e[x].end(),cmp);
30     g[x]=c[x];
31     for(unsigned i=0;i<e[x].size();i++) {
32         const int &y=e[x][i];
33         if(y==par) continue;
34         g[x]=std::max(g[x],f[x]+g[y]);
35         f[x]+=f[y];
36     }
37 }
38 int main() {
39     const int n=getint();
40     for(register int i=1;i<=n;i++) c[i]=getint();
41     for(register int i=1;i<n;i++) {
42         add_edge(getint(),getint());
43     }
44     dfs(1,0);
45     printf("%d\n",std::max(g[1],f[1]+c[1]));
46     return 0;
47 }

 

posted @ 2018-03-25 14:22  skylee03  阅读(114)  评论(0编辑  收藏  举报