题目链接:https://atcoder.jp/contests/arc098/tasks/arc098_d
题意:给你个图,每个点有(ai,bi),现在我有k元钱,每次我可以人选一个k>=ai点开始,可以捐赠bi,要求捐赠之后剩余钱>=0,问捐赠完所有点的最小的k是多少
题解:将两个限制变成一个限制ci -> max(ai-bi,0),这样走到一个点当且仅当 k>= ci,显然c应该从小到大选,发现用并查集维护之后可以dp
代码:
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
#define int LL
const int inf = 1e9,maxn=3e5+5;
int n,m,a[maxn],b[maxn],ra[maxn],dp[maxn];
struct edges{
int to,nxt;
}ed[maxn<<1];
vector<int>son[maxn];
int head[maxn],ecnt=0,id[maxn],fa[maxn],c[maxn],sz[maxn];
void add(int x,int y){ed[++ecnt].to=y;ed[ecnt].nxt=head[x];head[x]=ecnt;}
int find(int x){return fa[x] == x?fa[x]:fa[x] = find(fa[x]);}
int cmp(int x,int y){return c[x] < c[y];}
void dfs1(int x){
sz[x] += b[x];
for(int i=0;i<son[x].size();i++){
int u=son[x][i];
dfs1(u);
sz[x] += sz[u];
}
}
void dfs2(int x){
if(son[x].size() == 0){
dp[x] = b[x] + c[x];
return ;
}
dp[x] = 1e18;
for(int i=0;i<son[x].size();i++){
int u=son[x][i];
dfs2(u);
dp[x] = min(sz[x] - sz[u] + max(dp[u],c[x]),dp[x]);
}
}
void init(){
for(int i=1;i<=n;i++){
int u=id[i];
for(int j=head[u];~j;j=ed[j].nxt){
int v=ed[j].to;int fv = find(v), fu = find(u);
if(ra[fv] < ra[u] && fv != u){
son[u].push_back(fv);
fa[fv] = u;
}
}
}
}
signed main(){
memset(head,-1,sizeof head);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]), fa[i]=i, id[i]=i, c[i] = max(a[i]-b[i],0ll);
for(int i=1;i<=m;i++){
int x,y;scanf("%lld%lld",&x,&y);
add(x,y);add(y,x);
}
sort(id+1,id+n+1,cmp);
for(int i=1;i<=n;i++)ra[id[i]] = i;
// for(int i=1;i<=n;i++)printf("%d ",c[i]);puts("");
// for(int i=1;i<=n;i++)printf("%d ",id[i]);puts("");
init();
dfs1(id[n]);
dfs2(id[n]);
printf("%lld\n",dp[id[n]]);
return 0;
}