bzoj 3716: [PA2014]Muzeum 最小割/网络流+贪心+计算几何

网络流 同时被 3 个专栏收录
46 篇文章 0 订阅
51 篇文章 0 订阅
6 篇文章 0 订阅

题意

吉丽的漫展有n件手办和m名警卫。建立平面直角坐标系,每个手办和警卫都可以看做一个点。警卫们的目光都朝着y轴负方向,且都有相同大小的视角。警卫可以看见自己视角内(包括边界上的点)的所有手办,不用考虑视线的遮挡。
你打算抢劫吉丽的漫展,但不可被警卫发现。为了实施这次抢劫计划,你可以事先贿赂某些警卫,让他们闭上眼睛。只要某件手办不在任何睁着眼睛的警卫的视野内,你就可以偷走它。你知道每件手办的价格,以及每位警卫需要接受多少钱的贿赂。你想知道自己的最大收益是多少。
1<=n,m<=200000

分析

显然这是一个最大权闭合子图模型,建图是源点往警卫连流量为其价值的边,警卫往每个他能看到的手办连inf的边,每个手办往汇点连流量为其价值的边,那么最小割即为答案。
同时这个模型也可以看成是最大流,每个警卫看成一个有流量限制的水源,每个手办看成一个有容量限制的水桶,问最多可以往所有水桶里面流入多少水。
接下来我们可以先把坐标变换一下,把每个警卫的视线范围变成以该点为圆心时第二象限的形式,这样就好做很多了。
变换坐标的具体方式是,对于视线左边的那条射线,可以看成是一个向量(-w,-h),那么只要把每个点的两维坐标分别乘上h和w,就变成向量(-1,-1)。对右边的射线作同样处理,将其变成向量(1,-1)。然后再把坐标系旋转45度,就做完了。
这时就可以通过贪心来解决转化后的问题,只要按横坐标从小到大做,每加入一个警卫时,肯定是先流纵坐标尽量小的,直到全部水都流完了或没有桶可以流为止。
用一个set维护即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#define mp(x,y) make_pair(x,y)
using namespace std;

typedef long long LL;
typedef pair<LL,LL> pi;

const int N=200005;

int n,m;
LL w,h;
struct data{LL x,y,v;}a[N],b[N];
multiset<pi> se;
multiset<pi>::iterator it;

bool cmp(data a,data b)
{
    return a.x<b.x;
}

int main()
{
    scanf("%d%d",&n,&m);
    scanf("%lld%lld",&w,&h);
    LL ans=0;
    for (int i=1;i<=n;i++)
    {
        LL x,y,v;scanf("%lld%lld%lld",&x,&y,&v);
        x*=h;y*=w;a[i].x=x+y;a[i].y=x-y;a[i].v=v;ans+=v;
    }
    for (int i=1;i<=m;i++)
    {
        LL x,y,v;scanf("%lld%lld%lld",&x,&y,&v);
        x*=h;y*=w;b[i].x=x+y;b[i].y=x-y;b[i].v=v;
    }
    sort(a+1,a+n+1,cmp);
    sort(b+1,b+m+1,cmp);
    int p=1;
    for (int i=1;i<=m;i++)
    {
        while (p<=n&&a[p].x<=b[i].x) se.insert(mp(a[p].y,a[p].v)),p++;
        it=se.lower_bound(mp(b[i].y,0));LL ret=b[i].v;
        while (ret&&it!=se.end())
        {
            pi u=*it;se.erase(it);
            int f=min(u.second,ret);
            ret-=f;u.second-=f;ans-=f;
            if (u.second) se.insert(u);
            else it=se.lower_bound(mp(b[i].y,0));
        }
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值