【BZOJ3716】[PA2014]Muzeum(贪心,网络流)

【BZOJ3716】[PA2014]Muzeum(贪心,网络流)

题面

BZOJ

题解

很明显可以写最大权闭合子图,然后会\(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;
}
posted @ 2019-03-21 17:50  小蒟蒻yyb  阅读(294)  评论(0编辑  收藏  举报