2019 Multi-University Training Contest—6—1001— Salty Fish

好题,赞一波

解析:

我们思考最小割模型,源点向每个树上节点i连一条容量为ai的边,每个节点i向监视i的监控器连一条容量为inf的边,每个监控器j向汇点连一条容量为cj的边(这里的ai,cj都是原题中的定义)

我们只要跑最大流在用总苹果数减掉他就行了,但是由于点数过大,网络流会TLE 

我们考虑模拟一下网络流的过程,发现只要对于每个摄像头贪心选取还有流量且满足深度条件的最大深度的点,然后流向他即可。

具体维护只要开个map维护一下下标为深度还有多少流量可以流。但是这样貌似要两个log.

但是由于深度的条件,我们直接长链剖分,这样合并O(n),总的时间复杂度为(m+n)logn

#include
#define ll long long
#define pb(x) push_back(x)
#define mk(x,y) make_pair(x,y)
using namespace std;
const int N=3e5+10;
int dep[N],dep_max[N],hson[N];
vectore[N];
vector >q[N];
mapmp[N];
ll a[N];
ll ans,sum;
int T,n,m,x,k,c;
struct cmp{
	bool operator()(const pair &a,const pair &b){
		a.first::iterator it;
		for (it=mp[u].begin();it!=mp[u].end();it++) mp[top][it->first]+=it->second;
		mp[u].clear();
	}
	mp[top][n-dep[now]]+=a[now];
	for (int i=0;i<(int)q[now].size();i++){
		int k=q[now][i].first; ll c=q[now][i].second;
		ll t=c;
		map::iterator it;
		while (c&&!mp[top].empty()&&mp[top].lower_bound(n-dep[now]-k)!=mp[top].end()) {
			it=mp[top].lower_bound(n-dep[now]-k);
			if (c>=(it->second)) {
				c-=(it->second);  mp[top].erase(it);
			} else {
				(it->second)-=c; c=0; break;
			}
		}
		sum+=t-c;
	}
}
int main(){
	scanf("%d",&T);
	while (T--){
		scanf("%d%d",&n,&m);
		ans=0,sum=0; 
		for (int i=2;i<=n;i++) {scanf("%d",&x);e[x].pb(i);}
		for (int i=1;i<=n;i++) {
			scanf("%lld",&a[i]); ans+=a[i];
		}
		for (int i=1;i<=m;i++) {
			scanf("%d%d%d",&x,&k,&c); q[x].pb(mk(k,c));
		}
//		for (int i=1;i<=n;i++) sort(q[i].begin(),q[i].end(),greater >());
		dfs(1,0,1); dfs1(1,0,1);
		printf("%lld\n",ans-sum);
		mp[1].clear();
		for (int i=1;i<=n;i++) e[i].clear(),q[i].clear(),hson[i]=0;
	}
}

 

你可能感兴趣的:(长链剖分,网络流,hdu多校)