PA2014 Muzeum

如果不考虑复杂度,显然可以最大权闭合子图。
考虑最小割。
一个警卫向他可以看到的珠宝连inf边。
起点向警卫连贿赂费用的边。
珠宝向终点连价值的边。
把所有珠宝的价值加起来再减去最大流可以得到答案。
但是看到数据范围,这样子不太能做。
考虑最大流。先旋转坐标系,使得每个警卫只能看到横/纵坐标都比它小的手办。
问题转化成:有n个最多流出c[i]的水龙头,m个最多接受d[i]的点。
一个水龙头只能向横/纵坐标小于等于他的点流,询问最大流。
把水龙头按照x从小->大排序,在插入水龙头时更新网络流图。
插入一个水龙头后插入所有接受点。
显然每次向y坐标<=y且最大的点流最优。这样子接下来的点会更好流。
可以用set简单实现。
但是这样子的正确性不是很严格,本人不会证明。
如果可以证明可以告诉博主。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 200010
int n,m,w,ans,h;
struct no{
	int x,y,c;
}a[N],b[N];
int operator <(no x,no y){
	return x.x<y.x||(x.x==y.x&&x.y<y.y);
}
set<no>s;
signed main(){
	scanf("%lld%lld%lld%lld",&n,&m,&w,&h);
	for(int i=1;i<=n;i++){
		int x,y,c;
		scanf("%lld%lld%lld",&x,&y,&c);
		x*=h;
		y*=w;
		a[i].x=x+y;
		a[i].y=x-y;
		a[i].c=c;
		ans+=c;
	}
	for(int i=1;i<=m;i++){
		int x,y,c;
		scanf("%lld%lld%lld",&x,&y,&c);
		x*=h;
		y*=w;
		b[i].x=x+y;
		b[i].y=x-y;
		b[i].c=c;
	}
	sort(a+1,a+n+1);
	sort(b+1,b+m+1);
	int j=1;
	for(int i=1;i<=m;i++){
		while(j<=n&&a[j].x<=b[i].x){
			s.insert((no){a[j].y,j});
			j++;
		}
		while(!s.empty()&&b[i].c){
			auto it=s.lower_bound((no){b[i].y,0});
			if(it==s.end())
				break; 
			int x=(*it).y,va=min(b[i].c,a[x].c);
			b[i].c-=va;
			a[x].c-=va;
			ans-=va;
			if(!a[x].c)s.erase(it);
		}
	}
	printf("%lld\n",ans);
}
posted @ 2020-09-11 07:37  celerity1  阅读(74)  评论(0编辑  收藏  举报