IOI2021集训队作业 198EC Conquer the World
树上老鼠进洞问题。
要求每个老鼠必须要进一个洞,洞有容量,洞可以不满。
\(n\le 2.5*10^5\),\(\sum 老鼠\le10^6\)
其实和普通的老鼠进洞没有什么区别。不过加深了下对老鼠进洞的理解。
实际上可以认为老鼠和洞没有区别,只是老鼠必须全部进洞,此时让老鼠都带上\(-\infty\)的权即可。
用可并堆来维护。
在某个节点的时候,把它当做LCA统计。老鼠和洞的权值加上各自的\(dep\),在\(LCA\)处反正都要减去\(2dep_{lca}\)所以不会因为具体位置产生权值改变。
取出两个堆的堆顶加起来并减去\(2dep_{lca}\),如果小于\(0\)就进行配对,配对之后把反悔操作加入堆中。
using namespace std;
#include <bits/stdc++.h>
#define N 250005
#define ll long long
#define fi first
#define se second
#define mp(x,y) make_pair(x,y)
#define INF 1000000000000
int n;
struct EDGE{
int to,w;
EDGE *las;
} e[N*2];
int ne;
EDGE *last[N];
void lk(int u,int v,int w){
e[ne]={v,w,last[u]};
last[u]=e+ne++;
}
struct Node{
Node *l,*r;
int dep;
pair<ll,ll> v;
} *null;
int cnt;
Node *newnode(pair<ll,ll> v){
Node *nw=new Node;
*nw={null,null,0,v};
return nw;
}
Node *merge(Node *a,Node *b){
if (a==null) return b;
if (b==null) return a;
if (a->v>b->v) swap(a,b);
a->r=merge(a->r,b);
if (a->l->dep<a->r->dep)
swap(a->l,a->r);
a->dep=a->l->dep+1;
return a;
}
void push(Node *&t,pair<ll,ll> v){
Node *u=newnode(v);
t=merge(t,u);
}
void pop(Node *&t){
Node *u=t;
t=merge(u->l,u->r);
delete u;
}
Node *q0[N],*q1[N];
ll ans;
int a[N];
ll dep[N];
void dfs(int x,int fa){
q0[x]=q1[x]=null;
if (a[x]>0)
push(q0[x],mp(-INF+dep[x],a[x]));
else
push(q1[x],mp(dep[x],-a[x]));
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa){
dep[ei->to]=dep[x]+ei->w;
dfs(ei->to,x);
q0[x]=merge(q0[x],q0[ei->to]);
q1[x]=merge(q1[x],q1[ei->to]);
}
while (q0[x]!=null && q1[x]!=null && q0[x]->v.fi+q1[x]->v.fi-2*dep[x]<0){
pair<ll,ll> v0=q0[x]->v,v1=q1[x]->v;
pop(q0[x]);
pop(q1[x]);
ll tmp=min(v0.se,v1.se);
ans+=(v0.fi+v1.fi-2*dep[x])*tmp;
push(q0[x],mp(-(v0.fi+v1.fi-2*dep[x])+v0.fi,tmp));
push(q1[x],mp(-(v0.fi+v1.fi-2*dep[x])+v1.fi,tmp));
v0.se-=tmp,v1.se-=tmp;
if (v0.se) push(q0[x],v0);
if (v1.se) push(q1[x],v1);
}
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for (int i=1;i<n;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
lk(u,v,w),lk(v,u,w);
}
ll sum=0;
for (int i=1;i<=n;++i){
int x,y;
scanf("%d%d",&x,&y);
a[i]=y-x;
if (a[i]>0)
sum+=a[i];
}
null=new Node;
*null={null,null,0};
dfs(1,0);
ans+=sum*INF;
printf("%lld\n",ans);
return 0;
}