【BZOJ3716】[PA2014]Muzeum(贪心,网络流)
【BZOJ3716】[PA2014]Muzeum(贪心,网络流)
题面
题解
很明显可以写最大权闭合子图,然后会\(TLE\)成傻逼。
为了方便,就把一个警卫能够看到的范围处理一下(把坐标系处理一下),强制让他看到一个\(90°\)的夹角,再旋转一下就可以变成强制看到右下角的范围。
我们知道最大权闭合子图求出来的最小割=最大流。
那么我们来模拟这个过程,首先把所有警卫加入进来,其流量为贿赂他的代价。按照\(x\)轴排序之后,把所有它能够看到的宝物拿进来,然后考虑向谁流,会流向他能够看见的所有宝物中\(y\)最小的那个,大概证明就是你在这里多流了\(1\)不会比在后面多流\(1\)更差,然后\(y\)越大限制就越大,所以优先填限制最大的那个。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
#define MAX 200200
#define ll long long
#define pi pair<ll,ll>
#define mp make_pair
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Node{ll x,y,v;}a[MAX],b[MAX];
bool operator<(Node a,Node b){return a.x<b.x;}
ll ans;int n,m,w,h;
set<pi> S;
int main()
{
n=read();m=read();w=read();h=read();
for(int i=1;i<=n;++i)
{
ll x=1ll*read()*h,y=1ll*read()*w,v=read();
a[i]=(Node){x+y,x-y,v};ans+=v;
}
for(int i=1;i<=m;++i)
{
ll x=1ll*read()*h,y=1ll*read()*w,v=read();
b[i]=(Node){x+y,x-y,v};
}
sort(&a[1],&a[n+1]);sort(&b[1],&b[m+1]);
for(int i=1,j=1;i<=m;++i)
{
while(j<=n&&a[j].x<=b[i].x)S.insert(mp(a[j].y,a[j].v)),++j;
set<pi>::iterator it=S.lower_bound(mp(b[i].y,0));
ll flow=b[i].v;
while(flow&&it!=S.end())
{
pi q=*it;S.erase(it);
ll d=min(q.second,flow);
flow-=d;q.second-=d;ans-=d;
if(q.second)S.insert(q);
else it=S.lower_bound(mp(b[i].y,0));
}
}
printf("%lld\n",ans);
return 0;
}