HDU 5956 The Elder(斜率优化DP)

题目链接:



明显是一个斜率优化的形式,套一个斜率优化的板子就好了,重点是dfs的时候要记录操作,并且进行还原。


代码:

#include<bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int tot,head[MAXN],n,p,stk[MAXN],le,ri;
ll dp[MAXN],ans,sum[MAXN];
struct edge
{
	int to,nxt,w;
}E[MAXN*2];
void init()
{
	tot=0;
	memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
	E[tot].to=v;E[tot].w=w;E[tot].nxt=head[u];
	head[u]=tot++;
	E[tot].to=u;E[tot].w=w;E[tot].nxt=head[v];
	head[v]=tot++;
}
ll getUp(int k,int j)
{
	return (dp[k]+1LL*sum[k]*sum[k])-(dp[j]+1LL*sum[j]*sum[j]);
}
ll getDown(int k,int j)
{
	return sum[k]-sum[j];
}
void dfs(int now,int f)
{
	vector<pair<int,int> > sv;
	int l=le,r=ri;
	while(le+1<ri&&getUp(stk[le+1],stk[le])<=getDown(stk[le+1],stk[le])*2LL*sum[now])
	{
		sv.push_back(mp(le,stk[le]));
		le++;
	}
	if(now!=1)
	{
		dp[now]=dp[stk[le]]+(1LL*sum[now]-sum[stk[le]])*(1LL*sum[now]-sum[stk[le]])+p;
		ans=max(ans,dp[now]);
	}
	while(le+1<ri&&getUp(stk[ri-1],stk[ri-2])*getDown(now,stk[ri-1])>=getUp(now,stk[ri-1])*getDown(stk[ri-1],stk[ri-2]))
	{
		ri--;
		sv.push_back(mp(ri,stk[ri]));
	}
	stk[ri++]=now;
	for(int i=head[now];~i;i=E[i].nxt)
	{
		int v=E[i].to;
		if(v==f)
			continue;
		sum[v]=sum[now]+E[i].w;
		dfs(v,now);
	}
	le=l,ri=r;
	for(int i=0;i<sv.size();i++)
	{
		int pos=sv[i].xx,id=sv[i].yy;
		stk[pos]=id;
	}
}
void solve()
{
	init();
	scanf("%d%d",&n,&p);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		addedge(u,v,w);
	}
	le=ri=0;
	ans=0;
	dp[1]=-p;
	dfs(1,0);
	printf("%lld\n",ans);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值