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;
}
posted @ 2021-03-17 20:13  jz_597  阅读(108)  评论(0编辑  收藏  举报