1. 程式人生 > >Gym - 101002K:YATP (樹分治+二分+斜率優化)

Gym - 101002K:YATP (樹分治+二分+斜率優化)

給定 clu 這一 一個 mes 斜率優化 還要 printf clas

題意:給定帶點權邊權的樹,定義路徑的花費=路徑邊權和e+起點點權w[s]*終點點權w[t]。N<2e5,e,w<1e6;

思路:首先,需要樹分治。 然後得到方程dp[i]=min{ dis[i]+dis[j]+w[i]*w[j] },很顯然需要斜率優化。

註意維護凸包的時候是需要保證w[j]是單調的,這樣才能用不等式維護隊尾。 由於w[i]不是對應的隊尾,所以我們還要二分凸包。

還有個問題,怎麽確定我們得到的i和j不是在同一個子樹呢? 因為如果在一顆子樹的時候dp[i]=dis[i]+dis[j]+w[i]*w[j]-2*dis[LCA]。 其實沒必要考慮這個問題,因為當LCA為根的時候會更新答案。(這一點想不到估計要很難去維護了)

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=400010;
int Laxt[maxn],Next[maxn],To[maxn],Len[maxn],cnt;
int sz[maxn],son[maxn],rt,all,vis[maxn],S[maxn],tot;
ll ans[maxn],a[maxn],dis[maxn],sum; int q[maxn],top;
bool cmp(int x,int y) { int xx=x,yy=y; if(a[xx]==a[yy]) return dis[xx]<dis[yy]; return a[xx]<a[yy]; } ll getans(int p,int k) { return dis[k]+dis[p]+a[p]*a[k]; } void add(int u,int v,int w) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w; } void dfs1(int
u,int f) { sz[u]=1; son[u]=0; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f&&!vis[To[i]]) { dfs1(To[i],u); sz[u]+=sz[To[i]]; son[u]=max(son[u],sz[To[i]]); } } son[u]=max(son[u],all-son[u]); if(son[u]<son[rt]) rt=u; } void cal(int p) { if(top==0) return ;int L=1,R=top-1,Mid; ans[p]=min(ans[p],getans(p,q[top])); while(L<=R){ Mid=(L+R)>>1; ll tmp1=getans(p,q[Mid]),tmp2=getans(p,q[Mid+1]); if(tmp1<tmp2) R=Mid-1,ans[p]=min(ans[p],tmp1); else L=Mid+1,ans[p]=min(ans[p],tmp2); } } void get(int u,int f) { cal(u); for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f&&!vis[To[i]]) get(To[i],u); } bool check(int p){ return (dis[p]-dis[q[top]])*(a[p]-a[q[top-1]])<= (dis[p]-dis[q[top-1]])*(a[p]-a[q[top]]); } void ADD(int p) { if(top&&a[p]==a[q[top]]&&dis[p]<dis[q[top]]) top--; while(top>1&&check(p)) top--; q[++top]=p; } void get(int u,int f,ll D) { dis[u]=D; sz[u]=1; S[++tot]=u; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f&&!vis[To[i]]){ get(To[i],u,D+Len[i]); sz[u]+=sz[To[i]]; } } void solve(int u,int f) { vis[u]=1; dis[u]=0; top=0; tot=0; S[++tot]=u; for(int i=Laxt[u];i;i=Next[i]){ if(!vis[To[i]]&&To[i]!=f) get(To[i],u,Len[i]); } sort(S+1,S+tot+1,cmp); rep(i,1,tot) ADD(S[i]); rep(i,1,tot) cal(S[i]); for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(!vis[v]&&v!=f) { all=sz[v]; rt=0; dfs1(v,0); solve(rt,0); } } } int main() { int N,u,v,w; scanf("%d",&N); son[0]=N+1; rep(i,1,N) scanf("%lld",&a[i]); rep(i,1,N) ans[i]=a[i]*a[i]; rep(i,1,N-1){ scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } all=N; rt=0; dfs1(1,0); solve(rt,0); rep(i,1,N) sum+=ans[i]; printf("%lld\n",sum); return 0; }

Gym - 101002K:YATP (樹分治+二分+斜率優化)