AT4144 [ARC098D] Donation【2019集训队作业】

AT4144 [ARC098D] Donation【2019集训队作业】

C u = m a x { A u − B u , 0 } C_u=max\{A_u-B_u,0\} Cu=max{AuBu,0}

C u C_u Cu 的实际意义表示的是任意时刻 u u u 点的钱数都会大于 c u c_u cu

直接把 C C C 从小到大排序,然后建重构树即可。

d p x dp_x dpx 表示 x x x 子树内的答案。

那么有转移:

d p x = min ⁡ { s u m b x − s u m b y + max ⁡ { d p y , C x } } dp_x=\min\{sumb_x-sumb_y+\max\{dp_y,C_x\}\} dpx=min{sumbxsumby+max{dpy,Cx}}

s u m b x sumb_x sumbx 表示 x x x 子树内 B B B 的和。

选中的 y y y 就是我们最后遍历到的连通块,前面连通块遍历顺序不关心。

#include <bits/stdc++.h>
#define N 100005
using namespace std;
typedef long long ll;
int n,m;
struct node{
	int a,b,id;
}cc[N];
bool cmp_A(node x,node y){ 
	return x.a-x.b==y.a-y.b?x.id<y.id:x.a-x.b<y.a-y.b; 
}
vector<int> son[N],ed[N];
int fa[N],A[N],B[N],co[N];
ll ans[N],s[N];
int findf(int x){ return fa[x]==x?x:fa[x]=findf(fa[x]); }
void dfs(int x){
	int y; s[x]=B[x]; ans[x]=1e15;
	if(!ed[x].size()) ans[x]=max(A[x],B[x]); 
	for(int i=0;i<ed[x].size();i++){
		y=ed[x][i]; dfs(y); s[x]+=s[y];
	}
	for(int i=0;i<ed[x].size();i++){
		y=ed[x][i]; ans[x]=min(ans[x],s[x]-s[y]+max((ll)A[x]-B[x],ans[y]));
	}
//	cout<<x<<' '<<ans[x]<<'\n';
}
int main(){
//	freopen("test.in","r",stdin);
	cin>>n>>m;
	int u,v;
	for(int i=1;i<=n;i++) cin>>A[i]>>B[i],cc[i].a=A[i],cc[i].b=B[i],cc[i].id=i,fa[i]=i;
	for(int i=1;i<=m;i++){
		cin>>u>>v; 
		son[u].push_back(v),son[v].push_back(u);
	}
	sort(cc+1,cc+1+n,cmp_A);
	int x,y;
	for(int i=1;i<=n;i++){
		x=cc[i].id;
		for(int j=0;j<son[x].size();j++){
			y=son[x][j]; 
			if(A[y]-B[y]>A[x]-B[x]||(A[y]-B[y]==A[x]-B[x]&&y>x)) continue;
			if(findf(y)!=findf(x)){
				ed[x].push_back(fa[y]);
				fa[fa[y]]=fa[x];
			}
		}
	}
	dfs(findf(1));
	cout<<ans[findf(1)];
}
posted @ 2022-10-10 20:18  缙云山车神  阅读(17)  评论(0编辑  收藏  举报