ABC222F - Expensive Expense(换根DP)

ABC222F - Expensive Expense

解题思路

这个题是一道经典的换根 DP。这道题硬算是 \(O(n^2)\)。但是我们的时间限制要在 \(O(n)\) 以内。我们采用换根DP的技术。

首先我们先算出每个子树内的答案,再考虑每个子树外对答案的贡献。子树内的比较简单,主要思维难度在子树外部的答案计算上。

我们考虑现在计算根为 \(u\) 的子树。\(u\) 的父亲是 \(fa\),那么我们令状态为 \(g_u\),那么我们以 \(fa\) 为根时,维护出其每个子树的最大答案和次大的答案,然后扫一遍其原来树里的儿子。看起是不是最大答案,若是,那就用第二大的更新;否则用最大的更新。建议自己画图理解。我懒得画了

林外值得注意的是,每个节点不能以自己为终点,所以要注意一下。具体看代码。

最后注意一些细节,就可以了。

代码

//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
	char ch=getchar();
	int f=1,x=0;
	while(ch<'0'||ch>'9') {
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}

const int MAXN=2e5+10; 

int n,cnt;
int h[MAXN],f[MAXN],g[MAXN],fir[MAXN],sec[MAXN],mx[MAXN],c[MAXN];

struct edge {
	int to,w,nxt;
}e[MAXN<<1];

void addedge(int u,int v,int w) {
	e[++cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=h[u];
	h[u]=cnt;
}
void insert(int u,int v,int w) {
	addedge(u,v,w);
	addedge(v,u,w);
}

void dfs(int u,int fa) {
	mx[u]=c[u];
	for(int i=h[u];i;i=e[i].nxt) {
		int v=e[i].to;
		
		if(v!=fa) {
			dfs(v,u);
			mx[u]=max(mx[u],mx[v]+e[i].w);
			f[u]=max(f[u],mx[v]+e[i].w);
		}
	}
}
void efs(int u,int fa) {
	int a=0,b=0;
	for(int i=h[u];i;i=e[i].nxt) {
		int v=e[i].to;
		
		if(v!=fa) {
			if(mx[v]+e[i].w>fir[u]) {
				sec[u]=fir[u];
				b=a;
				a=v;
				fir[u]=mx[v]+e[i].w; 
			}
			else if(mx[v]+e[i].w>sec[u]) {
				b=v;
				sec[u]=mx[v]+e[i].w; 
			}
		}
	}
	for(int i=h[u];i;i=e[i].nxt) {
		int v=e[i].to;
		if(v!=fa) {
			g[v]=max((v==a? sec[u]:fir[u]),max(g[u],c[u]))+e[i].w;
			efs(v,u);
		}
	}
}

signed main() {
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);

	cin>>n;
	for(int i=1;i<n;i++) {
		int u,v,w;
		u=read(),v=read(),w=read();
		insert(u,v,w);
	}
	for(int i=1;i<=n;i++) {
		c[i]=read();
	}
	
	dfs(1,0);
	efs(1,0);
	
	for(int i=1;i<=n;i++) {
		printf("%lld\n",max(g[i],f[i]));
	}


	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
posted @ 2021-10-12 18:15  huayucaiji  阅读(101)  评论(0编辑  收藏  举报