1. 程式人生 > 其它 >jzoj5336-[NOIP2017提高A組模擬8.24]提米樹【dp】

jzoj5336-[NOIP2017提高A組模擬8.24]提米樹【dp】

正題

題目連結:https://gmoj.net/senior/#main/show/5336


題目大意

\(n\)個點的一棵樹,選擇一些節點作為葉子(割掉它的所有子節點)。

然後要求葉子的權值和減去相鄰葉子路徑之間(不算頭尾)最大權值最大。

\(1\leq n\leq 10^5\)


解題思路

有一個很簡單的\(O(n^2)dp\)就是設上一個葉子是\(f_x\)

然後考慮優化,相鄰葉子之間的路徑長度是小於\(2n\)的所以可以考慮處理這個東西。

我們用\(LCA\)到左邊葉子的路徑來更新到右邊葉子路徑上的\(f\)值,記\(mx_x\)表示\(LCA\)\(x\)節點的路徑最大權值,考慮到轉移式子中有一個\(max\{mx_l,mx_r\}\)

,而且這兩個在深度變大的時候單調不降,所以可以維護一個雙指標,滿足\(mx_i< mx_j\)然後前面的用\(mx_i\)轉移,後面的用\(mx_j\)轉移即可。

時間複雜度\(O(n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+10;
int n,k,cnt,tot,lf[N],w[N],fa[N],dep[N],dfn[N],rfn[N];
int f[N],mx[N],mf[N],mg[N],ans ;vector<int> G[N];
void dfs(int x){
	dep[x]=dep[fa[x]]+1;
	dfn[++cnt]=x;rfn[x]=cnt;
	for(int i=0;i<G[x].size();i++){
		int y=G[x][i];
		if(y==fa[x])continue;
		fa[y]=x;dfs(y);
		dfn[++cnt]=x;
	}
	if(G[x].empty())lf[++tot]=x;
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1,k;i<=n;i++){
		scanf("%d%d",&w[i],&k);
		for(int j=1;j<=k;j++){
			int x;scanf("%d",&x);
			G[i].push_back(x);
		}
	}
	dfs(1);
	for(int i=1;i<=rfn[lf[1]];i++)f[dfn[i]]=w[dfn[i]];
	for(int p=2;p<=tot;p++){
		int l=rfn[lf[p-1]],r=rfn[lf[p]],mid=l;
		for(int i=l+1;i<=r;i++)
			if(dep[dfn[i]]<dep[dfn[mid]])mid=i;
		mx[mid]=w[dfn[mid]];mf[mid-1]=f[dfn[mid-1]];
		for(int i=mid-1;i>=l;i--)mx[i]=max(mx[i+1],w[dfn[i+1]]);
		for(int i=mid+1;i<=r;i++)mx[i]=max(mx[i-1],w[dfn[i-1]]);
		for(int i=mid-2;i>=l;i--)mf[i]=max(mf[i+1],f[dfn[i]]);
		mg[l]=f[dfn[l]]-mx[l];
		for(int i=l+1;i<mid;i++)mg[i]=max(mg[i-1],f[dfn[i]]-mx[i]);
		//R.I.P
		for(int i=mid+1,j=mid-1;i<=r;i++){
			f[dfn[i]]=-1e9-7;
			while(j>=l&&mx[i]>=mx[j])j--;
			if(j<mid-1)f[dfn[i]]=mf[j+1]-mx[i];
			if(j>=l)f[dfn[i]]=max(f[dfn[i]],mg[j]);
			f[dfn[i]]+=w[dfn[i]];
		}
		//R.I.P
	}
	for(int i=rfn[lf[tot]];i<=cnt;i++)ans=max(ans,f[dfn[i]]);
	printf("%d\n",ans);
	return 0;
}
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P
//R.I.P