題意:給你一顆樹,每條邊有邊權,定義每條路徑長度爲路徑上相鄰邊 權值差的平方和。
樹dp加斜率優化
#include <bits/stdc++.h>
using namespace std;
#define N 200005
#define ll long long
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
struct no{
int to,n,w;
};no eg[N*2];
int h[N],tot=1,n;
void add(int u,int to,int w){
eg[++tot]={to,h[u],w};h[u]=tot++;
eg[++tot]={u,h[to],w};h[to]=tot++;
}
ll down[N],dis[N],up[N],dp[N];
void dfsdown(int u,int fa){
for(int i=h[u];i;i=eg[i].n){
int to=eg[i].to;
if(to==fa)continue;
dis[to]=eg[i].w;
dfsdown(to,u);
dp[u]=max(dp[u],down[to]);
down[u]=max(down[u],down[to]+(dis[u]-dis[to])*(dis[u]-dis[to]));
}
}
ll x(int u){return dis[u]; }
ll y(int u){return down[u]+dis[u]*dis[u]; }
ll dx(int a,int b){return x(a)-x(b); }
ll dy(int a,int b){return y(a)-y(b); }
bool cmp(int a,int b){return dis[a]<dis[b]; }
//up[to]+c[to]^2 = 2*c[u] *c[to] + up[u]-c[u]^2;
int qu[N],q[N];
void cal(int u,int fa){
int n=0;
for(int i=h[u];i;i=eg[i].n){
int to=eg[i].to;
if(to==fa)continue;
q[++n]=to;
if(fa)up[to]=up[u]+(dis[u]-dis[to])*(dis[u]-dis[to]);
}
sort(q+1,q+n+1,cmp);
int l=0,r=0;
go(i,1,n){
int u=q[i];
while(l<r-1&&dy(qu[r],qu[r-1])<2*dis[u]*dx(qu[r],qu[r-1]))r--;
if(l<r)up[u]=max(up[u],down[qu[r]]+(dis[u]-dis[qu[r]])*(dis[u]-dis[qu[r]]));
while(l<r-1&&dy(qu[r],qu[r-1])*dx(u,qu[r])<dy(u,qu[r])*dx(qu[r],qu[r-1]))r--;
qu[++r]=u;
}
l=0,r=0;
dep(i,n,1){
int u=q[i];
while(l<r-1&&dy(qu[r],qu[r-1])<2*dis[u]*dx(qu[r],qu[r-1]))r--;
if(l<r)up[u]=max(up[u],down[qu[r]]+(dis[u]-dis[qu[r]])*(dis[u]-dis[qu[r]]));
while(l<r-1&&dy(qu[r],qu[r-1])*dx(u,qu[r])>dy(u,qu[r])*dx(qu[r],qu[r-1]))r--;
qu[++r]=u;
}
dp[u]=max(dp[u],up[u]);
}
void dfsup(int u,int fa){
cal(u,fa);
for(int i=h[u];i;i=eg[i].n){
int to=eg[i].to;
if(to==fa)continue;
dfsup(to,u);
}
}
void init(){ go(i,1,n)dp[i]=up[i]=down[i]=h[i]=0;tot=1; }
int u,to,w;
int main()
{
while(cin>>n){
init();
go(i,2,n)scanf("%d%d%d",&u,&to,&w),add(u,to,w);
dfsdown(1,0);
dfsup(1,0);
go(i,1,n)printf("%lld\n",dp[i]);
}
return 0;
}
對每個結點的子節點排序之後,正反兩邊斜率dp。
網上對這裏的講解都不是很詳細
第一遍斜率dp的時候,維護的是上凸殼,
第二遍斜率dp的時候,維護的是下凸殼。
一開始沒弄懂爲什麼要這樣維護,後來發現是和x的遞增遞減,k的遞增遞減,取最大最小值有關的。
當x,k都單調時,
當x遞增,k遞增時,
取最大值,用棧維護上凸殼, 取最小值,用隊列維護下凸殼
當x遞增,k遞減時,
取最大值,用隊列維護上凸殼,取最小值,用棧維護下凸殼
當x遞減,可以當做斜率的方向全部改變了,然後方法和遞增是相反的。
當k不單調時,就需要二分在凸殼上找答案了。
當x也不單調2時,cdq?反正本弱雞不會