HDU 6634 网络流最小割模型 启发式合并
如果我们先手拿完所有苹果再去考虑花费的话。
S -> 摄像头 -> 苹果 -> T
就相当于找到一个最小割使得S和T分开。
ans = sum - flow。
然后对于这一个模型, 我们可以不用网络流去解决。
我们从叶子出发,然后从下往上合并。
每次到一个节点的时候,我们先把摄像机所对应的影响去除。
然后把这个点的剩下流量传给父亲。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 3e5 +100; //vector<int> vc[N]; vector<pll> camera[N]; map<int, LL> mp[N]; map<int, LL>::iterator it; int deep[N]; int a[N], f[N]; LL sum; void Merge(map<int, LL> & m1, map<int, LL> & m2){ if(m1.size() < m2.size()){ m1.swap(m2); } for(auto & it : m2){ m1[it.fi] += it.se; } } map<int,int> mp1, mp2; int main(){ int T, n, m; scanf("%d", &T); deep[1] = 1; while(T--){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) mp[i].clear(), camera[i].clear(); for(int i = 2; i <= n; ++i){ scanf("%d", &f[i]); deep[i] = deep[f[i]] + 1; } sum = 0; for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); sum += a[i]; } for(int i = 1, x, k, c; i <= m; ++i){ scanf("%d%d%d", &x, &k, &c); camera[x].pb({k, c}); } for(int i = n; i >= 1; --i){ mp[i][-deep[i]] += a[i]; for(auto & t : camera[i]){ it = mp[i].lower_bound(-(deep[i]+t.fi)); while(it != mp[i].end()){ if(t.se < (it->se)){ sum -= t.se; it -> se -= t.se; t.se = 0; break; } else { sum -= it->se; t.se -= it->se; it = mp[i].erase(it); } } } if(f[i]) Merge(mp[f[i]], mp[i]); } printf("%lld\n", sum); } return 0; }