传送门
题解:
设 f i ( x ) f_i(x) fi(x)表示在 i i i的子树中,所有叶子到 i i i距离为 x x x的时候,子树内部修改的最小代价。
显然是个分段一次函数,大力讨论记录下端点就行了。
注意到可能会出现需要平移端点的情况,但是我们发现这种情况永远都是发生在右边的,直接弹掉即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e6+7;
int n,m;
int now;
int lc[N],rc[N],ht[N];ll val[N];
inline int newnode(ll v){
val[++now]=v;return now;
}
inline int merge(int u,int v){
if(!u||!v)return u|v;
if(val[u]<val[v])std::swap(u,v);
rc[u]=merge(rc[u],v);
if(ht[rc[u]]>ht[lc[u]])std::swap(lc[u],rc[u]);
ht[u]=ht[rc[u]]+1;
return u;
}
inline void pop(int &rt){rt=merge(lc[rt],rc[rt]);}
ll ans;
int fa[N],d[N],w[N],rt[N];
ll st[N];int tp;
signed main(){
#ifdef zxyoi
freopen("hanabi.in","r",stdin);
#endif
n=gi(),m=gi();ht[0]=-1;
if(n+m==1){puts("0");return 0;}
for(int re i=2;i<=n+m;++i){++d[fa[i]=gi()];ans+=(w[i]=gi());}
for(int re i=n+m;i>1;--i){
ll l=0,r=0;
if(d[i]){
while(--d[i])pop(rt[i]);
r=val[rt[i]];pop(rt[i]);
l=val[rt[i]];pop(rt[i]);
}
rt[fa[i]]=merge(rt[fa[i]],rt[i]);
rt[fa[i]]=merge(rt[fa[i]],newnode(l+w[i]));
rt[fa[i]]=merge(rt[fa[i]],newnode(r+w[i]));
}
while(d[1]--)pop(rt[1]);
while(rt[1])st[++tp]=val[rt[1]],pop(rt[1]);
for(int re i=tp;i>=1;--i)ans-=(ll)i*(st[i]-st[i+1]);
cout<<ans<<"\n";
return 0;
}