P5996
网络流。同 P2762 太空飞行计划问题 建图方式,将物品与 连 ,警察与 连 ,警察与对应的物品连 ,答案为所有物品的收益和减最小割。割 表示不选物品,收益减 ;割 表示贿赂警察,收益减 ;警察与对应的物品的连边永远不被割,表示要么放弃物品要么贿赂警察。
,显然跑不了网络流。考虑模拟最大流。
首先要描述警察 与物品 的关系。要满足:
令 。得到 ,能很好描述。
将物品和警察放在一起从左到右,从上到下考虑,自然满足 。贪心,一个警察 的流优先从 且 最小处流过来,因为更大的 能满足更多人限制。用 set 储存物品,警察处 lower_bound 查找。set 的 erase 函数会返回删去的值的下一个的迭代器。
code
int n,m,w,h,ans;
struct nd{
int x,y,v,op;
}a[maxn];
bool cmp(nd u,nd v){
if(u.x!=v.x)return u.x<v.x;
return u.y>v.y;
}
set<pii> s;
void work(){
n=read();m=read();w=read();h=read();
for(int i=1;i<=n;i++){
int u=read(),v=read(),val=read();
a[i]={u*h+v*w,u*h-v*w,val,1};ans+=a[i].v;
}
for(int i=1;i<=m;i++){
int u=read(),v=read(),val=read();
a[i+n]={u*h+v*w,u*h-v*w,val,0};
}
sort(a+1,a+n+m+1,cmp);
for(int i=1;i<=n+m;i++){
if(a[i].op)s.insert({a[i].y,a[i].v});
else{
auto it=s.lower_bound({a[i].y,0});
while(a[i].v){
if(it==s.end())break;
pii p=*it;it=s.erase(it);
int d=min(a[i].v,p.second);
a[i].v-=d;p.second-=d;ans-=d;
if(p.second)s.insert(p);
}
}
}
printf("%lld\n",ans);
}