题解:P3006 [USACO11JAN] Bottleneck G
比较容易使人思维弄混的一个题。
贪心策略肯定对于任意一个点,只要能往上跑就往上跑,也就是尽量让每一条边都满流。这样直接模拟的话是
但复杂度肯定不可能带
由于这个树形 dp 依赖于
然后我们考虑一个这样的树:
很明显在二号点出现“入不敷出”的情况之前,
更一般地,若
通过干这样一件事情,我们保证了当前所有节点都会进行下一次流出(除非已经全部流到
复杂度是
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
int n,i,j,ans,k,Q,t,s,m[N],c[N],p[N],g[N],res[N];
std::priority_queue<pii>q;
struct ren{
int t,w;
bool operator < (const ren &A) const{
return t < A.t;
}
}d[N];
struct DSU{
int f[N];
void init(){
for(int i=1;i<=n;i++) f[i]=i;
return;
}
int find(int x){
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
}dsu;
signed main(){
scanf("%lld%lld",&n,&Q);
for(i=2;i<=n;i++){
scanf("%lld%lld%lld",&p[i],&c[i],&m[i]);
g[p[i]]-=m[i],g[i]+=m[i],s+=c[i];
}
for(i=1;i<=n;i++){
if(g[i]>0) q.push({-c[i]/g[i],i});
}
for(i=1;i<=Q;i++) scanf("%lld",&d[i].t),d[i].w=i;
sort(d+1,d+1+Q);
dsu.init();
for(i=1;i<=Q;i++){
while(!q.empty() && -q.top().fi<d[i].t){//只能<
int x=q.top().se;
q.pop();
if(dsu.f[x]!=x) continue;
int k=dsu.find(p[x]);
g[k]+=g[x],c[k]+=c[x],dsu.f[x]=k;
if(g[k]>0) q.push({-c[k]/g[k],k});
}
res[d[i].w]=min(s,c[1]-g[1]*d[i].t);
}
for(i=1;i<=Q;i++) printf("%lld\n",res[i]);
return 0;
}