[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 }