[HDU5956]The Elder

题面在这里

题意

一个王国中的所有城市构成了一棵有根树,其根节点为首都,编号为1
树有边权,城市的记者每次向祖先移动(d)的路程需要的代价为(d^2)
如果祖先不是根还需要加上(p),求每个非根节点的记者移动到首都的最小代价

sol

考虑朴素的DP,设(f[i])表示第(i)号节点到达根节点的最小代价,
(s[i])表示(i)到根节点的距离,那么有

[f[i]=min_{jin ancestor(i)}(f[j]+(s[i]-s[j])^2+p) ]

初始状态为(f[1]=-p)

斜率优化:

[f[i]=min_{jin ancestor(i)}(f[j]+s[j]^2-2s[i]s[j])+s[i]^2+p ]

那么考虑插点((2s[j],f[j]+s[j]^2)),询问斜率(k_i=s[i]);

树上斜率优化——可持久化单调队列

由于是在树上做,那么我们需要支持撤销前一次的操作;
我们对于记录一个栈,记录推到这个节点时弹出了哪些节点,
撤回的时候在队列中删掉当前节点,把之前弹出的节点放回去即可
这样的时间复杂度应该仍为(O(n))

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int N=1000010;
il ll read(){
	RG ll data=0,w=1;RG char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
	return data*w;
}

il void file(){
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
}

ll T,n,p,f[N],s[N];
int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnt;
il void add(ll u,ll v,ll w){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	val[cnt]=w;
	head[u]=cnt;
}

int L=1,R;ll qx[N],qy[N];
int cal[N],top;ll calx[N],caly[N];
il void cancel(int u){
	R--;
	while(cal[top]==u){
		R++;qx[R]=calx[top];qy[R]=caly[top];top--;
	}
}

il void insert(int u,ll x,ll y){
	while(L<R&&(qy[R]-qy[R-1])*(x-qx[R])>=(y-qy[R])*(qx[R]-qx[R-1])){
		cal[++top]=u;calx[top]=qx[R];caly[top]=qy[R];R--;
	}
	R++;qx[R]=x;qy[R]=y;
}

il int check(ll k,int mid){
	if(mid!=R&&k*(qx[mid+1]-qx[mid])>qy[mid+1]-qy[mid])
	    return 1;
	if(mid!=L&&k*(qx[mid]-qx[mid-1])<qy[mid]-qy[mid-1])
	    return -1;
	return 0;
}
//二分斜率
il ll query(ll k){
	RG int l=L,r=R,mid,ret;
	while(l<=r){
		mid=(l+r)>>1;
		ret=check(k,mid);
		if(!ret)return qy[mid]-k*qx[mid];
		else if(ret==1)l=mid+1;
		else if(ret==-1)r=mid-1;
	}
}

void dfs_DP(int u,int fa){
	if(u!=1){
		f[u]=query(s[u])+s[u]*s[u]+p;
		insert(u,2*s[u],f[u]+s[u]*s[u]);
	}
	else insert(u,0,-p);
	for(RG int i=head[u];i;i=nxt[i]){
		RG int v=to[i];if(v==fa)continue;
		s[v]=s[u]+val[i];dfs_DP(v,u);
	}
	cancel(u);
}

il void solve(){
	memset(head,0,sizeof(head));cnt=0;L=1;R=0;
	n=read();p=read();
	RG ll u,v,w;
	for(RG int i=1;i<n;i++){
		u=read();v=read();w=read();
		add(u,v,w);add(v,u,w);
	}

	dfs_DP(1,0);
	
	RG ll maxn=0;
	for(RG int i=1;i<=n;i++)
		maxn=max(maxn,f[i]);
	printf("%lld
",maxn);
}

int main()
{
	T=read();while(T--)solve();return 0;
}

原文地址:https://www.cnblogs.com/cjfdf/p/8671890.html