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);
}